Будущее /async/ожидание в Dart

У меня есть функция loadData которая загружает некоторый текст из файла:

Future<String> loadAsset() async {
  return await rootBundle.loadString('assets/data/entities.json');
}

Метод loadString - от Flutter SDK и является асинхронным.

Затем метод loadAsset вызывается другим методом, который должен быть помечен как async, поскольку loadAsset является асинхронным, и мне нужно использовать await:

Future<List<Entity>> loadEntities() async {
  String jsonData = await loadAsset();
  return parseData(jsonData);
}

Метод parseData не является асинхронным, он получает String, анализирует ее и возвращает список объектов:

List<Entity> parseData(String jsonString) {
  ...
}

Но поскольку loadEntities должен быть помечен async, для этого требуется, чтобы он возвращал Future, но на практике это не Future потому что, поскольку я использую await, он ждет loadAsset метода loadAsset, а затем вызовет parseData с использованием результата.

Это легко превращается в снежный ком async вызова, потому что каждый метод, который использует loadEntities должен быть помечен как async.

Кроме того, я не могу использовать loadEntities в конструкторе класса, потому что конструктор должен быть помечен как async, что запрещено в Dart.

Я использую шаблон async/await в Dart неправильно? Как я могу использовать метод loadEntities в конструкторе класса?

Ответ 1

Нет, async заразителен, и нет возможности вернуться от асинхронного к синхронизации.

async/await - это только синтаксический сахар для methodThatReturnsFuture().then(...)

Маркировка метода с помощью async - это только позволить вам использовать await внутри своего тела. Без async вам все равно нужно вернуть Future для вызова кода только после того, как будет loadAsset() результат loadAsset().

Ответ 2

Вы можете использовать Будущее, возвращенное из асинхронного вызова напрямую. Это будет выглядеть примерно так:

class HasAsync {
  HasAsync() {
    asyncFunction().then((val) {
      print(val);
    });
  }

  Future<int> asyncFunction() async {
     int val = await otherFunction();
     return val;
  }
}

Вы просто не можете использовать ожидание внутри функции non-async.

Поскольку вы отметили это с помощью флаттера, я собираюсь угадать, что это приложение для флаттера. Если этот случай рассмотрит документы для FutureBuilder - это может помочь в том, что вы пытаетесь сделать.

Ответ 3

Просто исправление: асинхронные методы НЕ заразны. Конструктор Test вызывает асинхронный метод sayHello. Это демонстрирует, как заставить ctor сделать асинхронный вызов, когда его нельзя объявить асинхронным. Основной метод помечается как асинхронный просто, чтобы приложение не закрывалось до завершения sayHello. Это не внутреннее требование.

class Test
{
  Test()
  {
    sayHello();
  }

  void sayHello() async
  {
    await Future.delayed(Duration(seconds: 4) , () => print("Hello"));

    print("We said hello");
  }

}

  void main() async
  {

    doTest();

  // wait for hello to be output
    await Future.delayed(Duration(seconds: 6) , ()  {});

    print("Ending");
  }

  void doTest()
  {
        Test();
  }

Ответ 4

У меня есть статья, объясняющая это https://medium.com/@truongsinh/flutter-dart-async-concurrency-demystify-1cc739aaae57

Короче говоря, Flutter/Dart не является технически однопоточным, хотя код Dart выполняется в одном потоке. Dart - это параллельный язык с шаблоном передачи сообщений, который может в полной мере использовать преимущества современной многоядерной архитектуры, не беспокоясь о блокировке или мьютексе. Блокировка в Dart может быть привязана либо к I/O, либо к CPU, что должно быть решено, соответственно, вычислениями Future и Darts Isolate/Flutters.