DevGang
Авторизоваться

Учебник Dart Future с примерами

Асинхронное программирование позволяет программе выполнять работу, ожидая завершения чего-то другого. В этом уроке мы покажем вам, как работать с Future в Dart (также с Flutter). В конце концов ты узнаешь:

  • Введение в Dart Future
  • Как создать методы Future, Future delayed и value
  • Основное использование Future: then, catchError и callback
  • Способ использования Future async-await
  • Future multiple await/then for chain of multiple асинхронных методов
  • Эквивалент «наконец-то»: Future whenComplete
  • Future wait для завершения нескольких фьючерсов

Обзор Dart Future

Future представляет собой потенциальное значение (success), или ошибку (fail), которые будут доступны в будущем. Как правило нам нужно будет работать с будущей стоимостью в следующих случаях:

  • получение данных с сервера
  • запрос данных из базы данных
  • чтение файла
  • выполнение сложной вычислительной работы
Future<int> future = getFuture();
Future<Tutorial> tutorialsFut = getTutorialsFromDatabase(query);
Future<Data> dataFut = fetchDataFromServer(url);
Future<int> resultFut = computeBigData(value);

Dart Future then

Мы можем использовать then(), чтобы указать код, который выполняется после завершения future. 

Для примера, fetchDataFromServer() возвращает значение Future.

Future<Data> future = fetchDataFromServer(url);
future.then((Data data) {
  print(data.values);
});

Dart Future callback

В приведенном выше примере мы регистрируем callback, который обрабатывает значение Future результата. Как насчет ошибки? Мы собираемся использовать catchError(callback).

Например:

Future<Data> future = fetchDataFromServer(url);
future.then((data) => handleData(data))
      .catchError((error) => handleError(error));

Dart async-await

Ключевые слова async и await предоставляют декларативный способ определения асинхронной функции (которая возвращает Future) и использования ее результата.

 Мы должны помнить два основных условия:

  1. Асинхронная функция имеет async перед телом функции
  2. Ключевое слово await работает только в async функции

Например, мы собираемся переписать Future с использованием стиля async-await.

main() async {
  Data data = await fetchDataFromServer(url);
  handleData(data);
}

Кроме того, then-catchError эквивалентен async-await следующим образом:

main() async {
  try {
    Data data = await fetchDataFromServer(url);
    handleData(data);
  } catch (error) {
    handleError(error);
  }
}

Давайте продолжим с некоторыми простыми способами создания:

Dart Future delayed

Future<T>.delayed(Duration duration, [computation()?])

Метод delayed() создает Future, который запускает вычисления по истечении заданного времени, и future завершается с результатом вычисления.

Если duration равно 0 или меньше, она завершается не раньше, чем на следующей event-loop итерации, после выполнения всех микрозадач.

Например:

Future.delayed(Duration(seconds: 2), () => 'Delayed 2 seconds.')
      .then((result) => print(result));

async-await:

var result = await Future.delayed(Duration(seconds: 2), () => 'Delayed 2 seconds.');
print(result);

Вывод:

(after 2 seconds)
Delayed 2 seconds.

Dart Future value

Future<T>.value(value)

Метод Future.value() создает Future дополненное с value.

Например:

Future.value("bezkoder.com")
      .then((result) => print(result));

async-await:

var result = await Future.value("bezkoder.com");
print(result);

Вывод:

bezkoder.com

Dart Future error

Future.error(Object error) создает future, которое завершается с error.

Например:

Future.error('> This is an error message!')
      .catchError((err) => print(err));

async-await:

try {
  await Future.error('> This is an error message!');
} catch (err) {
  print(err);
}

Вывод:

> This is an error message!

Напишите асинхронную функцию с Future

Теперь мы создадим асинхронную функцию, которая возвращает Future. Функция получает входной номер int. Если введенное число меньше 0, оно завершается ошибкой Future, или же завершается через заданное времяи возвращает введенное число.

Future<int> doInSeconds(int sec) {
  print('> Processing with value=${sec}...');

  if (sec <= 0) {
    return Future.error('> input \'sec\' must be greater than 0');
  }

  return Future.delayed(Duration(seconds: sec), () {
    print('> Something done in ${sec} second(s).');
    return sec;
  });
}

Давайте воспользуемся функцией doInSeconds()

doInSeconds(2).then((result) {
  print(result);
}).catchError((error) {
  print('> inside catchError');
  print(error);
});

или 

try {
  var result = await doInSeconds(2);
  print(result);
} catch (error) {
  print(error);
}

Вывод:

> Processing with value=2...
(after 2 seconds)
> Something done in 2 second(s).
2

Проверьте Error:

try {
  var result = await doInSeconds(-1);
  print(result);
} catch (error) {
  print('> inside catchError');
  print(error);
}

Вывод:

> Processing with value=-1...
> inside catchError
> input 'sec' must be greater than 0

Цепочка из нескольких асинхронных методов в Dart

Вот так мы справляемся со случаем, когда нам нужно вызвать несколько асинхронных функций в определенном порядке.

Future future = doInSeconds(1);
future
    .then((v1) => doInSeconds(v1 + 1))
    .then((v2) => doInSeconds(v2 + 1))
    .catchError((error) => print(error));

Вывод:

> Processing with value=1...
> Something done in 1 second(s).
> Processing with value=2...
> Something done in 2 second(s).
> Processing with value=3...
> Something done in 3 second(s).
  • Если обратный вызов внутри then() возвращает Future, то then() возвращает Future, который завершится тем же результатом.
  • Если обратный вызов возвращает значение любого другого типа, то then() создает новый Future, который завершается value.

Dart multiple await

Давайте запустим multiple асинхронных функций в цепочке, используя async-await:

try {
  final v1 = await doInSeconds(1);
  final v2 = await doInSeconds(v1 + 1);
  await doInSeconds(v2 + 1);
} catch (error) {
  print(error);
}

Вывод:

> Processing with value=1...
> Something done in 1 second(s).
> Processing with value=2...
> Something done in 2 second(s).
> Processing with value=3...
> Something done in 3 second(s).

Dart Future whenComplete

Мы знаем, что then-catchError эквивалентен try-catch, так что whenComplete используется для finally.

Обратный вызов внутри whenComplete() вызывает после все, независимо от того, является ли результат value или error.

try-catch-finally:

try {
  final v1 = await doInSeconds(1);
  final v2 = await doInSeconds(v1 + 1);
  await doInSeconds(v2 + 1);
} catch (error) {
  print(error);
} finally {
  print("Done!");
}

эквивалент:

Future future = doInSeconds(1);
future
    .then((v1) => doInSeconds(v1 + 1))
    .then((v2) => doInSeconds(v2 + 1))
    .catchError((error) => print(error))
    .whenComplete(() => print("Done!"));

Вывод:

> Processing with value=1...
> Something done in 1 second(s).
> Processing with value=2...
> Something done in 2 second(s).
> Processing with value=3...
> Something done in 3 second(s).
Done!

Проверьте другой код, который вызовет ошибку.

Future future = doInSeconds(1);
future
    .then((v1) => doInSeconds(v1 - 1))
    .then((v2) => doInSeconds(v2 - 1))
    .catchError((error) => print(error))
    .whenComplete(() => print("Done!"));

Вывод:

> Processing with value=1...
> Something done in 1 second(s).
> Processing with value=0...
> input 'sec' must be greater than 0
Done!

Future ждать в Dart

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

var query = doInSeconds;
var compute = doInSeconds;
var work = doInSeconds;
await Future.wait([
  query(1),
  compute(6),
  work(3),
]);
print('Done!');

Вывод:

> Processing with value=1...
> Processing with value=6...
> Processing with value=3...
> Something done in 1 second(s).
> Something done in 3 second(s).
> Something done in 6 second(s).
Done!

Вывод

В этом руководстве мы изучили обзор Dart/Flutter Future, как создать Future, просто используя методы delayed или value, как работать с then-catchError-whenComplete или try-catch-finally с Future async-await, как для обработки цепочки multiple асинхронных методов или ожидания завершения нескольких фьючерсов.

#Flutter
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В подарок 100$ на счет при регистрации

Получить