Pull to refresh

Асинхронное программирование в Dart (часть 1)

Reading time 3 min
Views 16K
image

В данной серии статей я не буду касаться азов программирования на самом Dart, а коснусь вопросов асинхронности в Dart.

Библиотеки Dart полны функций, которые возвращают Future или Stream объекты. Эти функции асинхронны.

В документации читаем:

Future — подобен обещанию когда-то в будущем предоставить результат.
Stream — это способ получить последовательность значений, таких как, например, последовательность событий (поток).

Future и Stream входят в библиотеку dart:async, которую можно использовать как в скриптах веб-приложений, так и в скриптах, запускаемых из консоли.

Импортируем библиотеку так:

import 'dart:async';


Future


В библиотеках Dart полно функций возвращающих Future. Когда future-объект завершается (какая-то операция), его значение готово к использованию. Причем работать с Future можно разными способами.

Использовать async и await


Это, наверное, самый простой и понятный способ обработки future-объектов. Он очень похож на синхронный.

someFunction() async {
  var someVar = await functionXXL();
  if (someVar == someParam) {
    // Делаем что-то.
  } else {
    // Делаем что-то.
  }
}

В чем суть await: await ожидает возвращения результата асинхронной функции.

async функция (someFunction() — в нашем примере) фактически возвращает сразу, до того, как выполнятся асинхронные операции внутри нее, но возвращает она Future, т.е. возвращает «обещание» вернуть определенные значения позже, когда асинхронные процессы будут завершены.

Внутри функции с ключевым словом async мы можем запустить один или несколько асинхронных процессов. Другими словами конструкций await может быть много (пример из оригинальной документации):

runUsingAsyncAwait() async {
  //...
  var entrypoint = await findEntrypoint();
  var exitCode = await runExecutable(entrypoint, args);
  await flushThenExit(exitCode);
}

Важно обратить внимание на следующее:

1. await работает только внутри тела функции, которое предварено ключевым словом async.
2. await конструкции выполняются в том же логическом порядке, как они написаны. Т.е. пока не выполнился один await управление не передается следующему.
3. async функции всегда возвращают Future. Если мы не хотим, чтобы наша функция возвращала Future, можно использовать различные решения для этого, например, мы можем вызвать async функцию из другой (не async) функции.

Теперь давайте посмотрим, как происходит обработка ошибок в async функциях:

someFunc() async {
// какая-то логика
  try {
    await someObject.start();
  } catch (e) {
    // управление ошибками
  }
}

Используем метод Future — then()


Этот вариант имеет воплощение более похожее на асинхронное. Рассмотрим на примере (пример из оригинальной документации):

HttpRequest.getString(url).then((String result) {
  print(result);
}).catchError((e) {
  // Обрабатываем или игнорируем ошибку.
});

В этом примере HttpRequest.getString(url) возвращает Future. Когда Future завершается, метод then() выполняет некоторый код, в нашем случае выводит строку в консоль. Обратите внимание на, что обработка ошибок в этом случае происходит в конструкции catchError.

Шаблон then().catchError() является сам по себе асинхронной версией try-catch.

Метод then() возвращает Future, обеспечивая удобный способ запуска нескольких асинхронных функций в определенном порядке. Если функция обратного вызова (callback), зарегистрированная в then(), возвращает Future, then() возвращает эквивалентный Future. Если callback возвращает значение любого другого типа, then() создает новый Future, который завершается с этим значением.

Опять пример из оригинальной документации:

Future result = costlyQuery();

return result.then((value) => expensiveWork())
             .then((value) => lengthyComputation())
             .then((value) => print('done!'))
             .catchError((exception) => print('DOH!'));

Здесь мы видим «сцепление» нескольких .then().

Функции в этом примере отрабатывают в следующем порядке:

1. costlyQuery()
2. expensiveWork()
3. lengthyComputation()

Используем метод Future.wait()


Если нам нужно выполнить несколько асинхронных функций, а по окончании их выполнения выполнить некоторый код, можно использовать статический метод Future.wait(). Пример:

Future func1 = doSmth1();
Future func2 = doSmth2();
Future func3 = doSmth3();;

Future.wait([func1, func2, func3])
    .then((List values) {
      print('Отработали!');
    });

Ссылки по теме


Асинхронное программирование Dart (eng): (ссылка 1, ссылка 2).
Также можно почитать: (ссылка 3, ссылка 4)

Я не гуру в Dart, поэтому буду очень благодарен за ваши замечания, уточнения и предложения. Спасибо за внимание.
Tags:
Hubs:
+16
Comments 12
Comments Comments 12

Articles