Вызов метода async из конструктора компонента в Dart

Предположим, что инициализация MyComponent в Dart требует отправки HttpRequest на сервер. Можно ли синхронно построить объект и отложить "реальную" инициализацию до возвращения ответа?

В приведенном ниже примере функция _init() не вызывается до тех пор, пока не будет напечатана "done". Можно ли это исправить?

import 'dart:async';
import 'dart:io';

class MyComponent{
  MyComponent() {
    _init();
  }

  Future _init() async {
    print("init");
  }
}

void main() {
  var c = new MyComponent();
  sleep(const Duration(seconds: 1));
  print("done");
}

Выход

done
init

Ответ 1

Конструктор может возвращать только экземпляр класса, он является конструктором (MyComponent). Для вашего требования потребуется, чтобы конструктор возвращал Future<MyComponent>, который не поддерживается.

Вам нужно либо сделать явный метод инициализации, который должен вызывать пользователь вашего класса, например:

class MyComponent{
  MyComponent();

  Future init() async {
    print("init");
  }
}

void main() async {
  var c = new MyComponent();
  await c.init();
  print("done");
}

или вы начинаете инициализацию в consturctor и позволяете пользователю компонента ждать завершения инициализации.

class MyComponent{
  Future _doneFuture;

  MyComponent() {
    _doneFuture = _init();
  }

  Future _init() async {
    print("init");
  }

  Future get initializationDone => _doneFuture
}

void main() async {
  var c = new MyComponent();
  await c.initializationDone;
  print("done");
}

Когда _doneFuture уже завершено, await c.initializationDone возвращается немедленно, иначе он ожидает, что будущее будет завершено первым.

Ответ 2

Вы можете использовать _init() как метод static. Это может быть более точным решением вашей проблемы:

import 'dart:async';
import 'dart:io';

class MyComponent{
  MyComponent();
  static Future init() async {
    print("init");
  }
}

void main() async {
  var c = await MyComponent.init();
  sleep(const Duration(seconds: 1));
  print("done");
}

Не забудьте пометить функцию, которую вы используете в init() как асинхронную.