Класс Future< T>
Результат асинхронного вычисления.
Асинхронное вычисление не может предоставить результат немедленно после запуска, в отличие от синхронного вычисления, которое вычисляет результат немедленно, возвращая значение или выбрасывая исключение. Асинхронное вычисление может потребовать ожидания внешнего события (чтения файла, запроса к базе данных, получения веб-страницы), что занимает время. Вместо того, чтобы блокировать всю вычислительную систему до получения результата, асинхронное вычисление немедленно возвращает Future, который в конечном итоге "завершится" результатом.
Асинхронное программирование
Для выполнения асинхронного вычисления используется async функция, которая всегда возвращает объект Future. Внутри такой асинхронной функции вы можете использовать операцию await для отсрочки выполнения до получения результата от другого асинхронного вычисления. Хотя выполнение ожидающей функции откладывается, программа не блокируется и может продолжать другие задачи.
Пример:
import "dart:io";
Future<bool> fileContains(String path, String needle) async {
var haystack = await File(path).readAsString();
return haystack.contains(needle);
} Здесь метод File.readAsString из dart:io — это асинхронная функция, возвращающая Future<String>. Функция fileContains помечена async непосредственно перед её телом, что означает, что вы можете использовать await внутри неё и что она должна возвращать объект Future. Вызов File(path).readAsString() инициирует чтение файла в строку и создаёт Future<String>, который в конечном итоге будет содержать результат. Функция await ожидает завершения этого объекта Future со строкой (или ошибки, если чтение файла завершилось ошибкой). Пока ожидается, программа может выполнять другие задачи. Когда объект Future завершается со строкой, функция fileContains вычисляет булево значение и возвращает его, что затем завершает исходный объект Future, который она вернула при первом вызове.
Если объект Future завершается с ошибкой, ожидание этого объекта Future (пере)выбросит эту ошибку. В примере здесь можно добавить проверку ошибок:
import "dart:io";
Future<bool> fileContains(String path, String needle) async {
try {
var haystack = await File(path).readAsString();
return haystack.contains(needle);
} on FileSystemException catch (exception, stack) {
_myLog.logError(exception, stack);
return false;
}
} Вы используете обычный try/catch для обработки ошибок ожидаемых асинхронных вычислений.
В общем случае, при написании асинхронного кода вы всегда должны ожидать объект Future при его создании, а не ждать после другого асинхронного действия. Это гарантирует, что вы готовы принять любую ошибку, которую может выдать объект Future, что важно, так как асинхронная ошибка, на которую никто не ждёт, является необработанной ошибкой и может завершить выполнение программы.
Работа с API Future
Класс Future также предоставляет более прямой, низкоуровневый функционал для доступа к результату, с которым он завершается. async и await языковые особенности основаны на этом функционале, и иногда имеет смысл использовать его напрямую. Есть задачи, которые вы не сможете выполнить, просто ожидая один объект Future за другим.
С объектом Future можно вручную зарегистрировать обработчики, которые обрабатывают значение или ошибку, как только они станут доступны. Например:
Future<int> future = getFuture();
future.then((value) => handleValue(value))
.catchError((error) => handleError(error)); Поскольку объект Future может завершаться двумя способами, либо со значением (если асинхронное вычисление успешно), либо с ошибкой (если вычисление завершилось ошибкой), вы можете установить обработчики для каждого из этих случаев.
В некоторых случаях мы говорим, что объект Future завершается другим объектом Future. Это краткое описание того, что объект Future завершается так же, со тем же значением или ошибкой, что и другой объект Future, как только этот другой объект Future завершается. Большинство функций в библиотеках платформы, которые завершают объект Future (например, Completer.complete или Future.value), также принимают другой объект Future и автоматически пересылает результат завершаемому объекту Future.
Результат регистрации обработчиков сам по себе является объектом Future, который, в свою очередь, завершается результатом вызова соответствующего обработчика с результатом исходного объекта Future. Новый объект Future завершается ошибкой, если вызываемый обработчик выбрасывает исключение. Например:
Future<int> successor = future.then((int value) {
// Invoked when the future is completed with a value.
return 42; // The successor is completed with the value 42.
},
onError: (e) {
// Invoked when the future is completed with an error.
if (canHandle(e)) {
return 499; // The successor is completed with the value 499.
} else {
throw e; // The successor is completed with the error e.
}
}); Если у объекта Future нет зарегистрированных обработчиков при завершении с ошибкой, он пересылает ошибку в "обработчик необработанных ошибок". Это поведение гарантирует, что ни одна ошибка не будет пропущена. Однако это также означает, что обработчики ошибок должны быть установлены заранее, чтобы они присутствовали, как только объект Future завершится с ошибкой. Следующий пример демонстрирует эту потенциальную ошибку:
var future = getFuture();
Timer(const Duration(milliseconds: 5), () {
// The error-handler is not attached until 5 ms after the future has
// been received. If the future fails before that, the error is
// forwarded to the global error-handler, even though there is code
// (just below) to eventually handle the error.
future.then((value) { useValue(value); },
onError: (e) { handleError(e); });
}); При регистрации обработчиков часто более удобно регистрировать два обработчика отдельно, сначала используя then со одним аргументом (обработчик значения) и второе catchError для обработки ошибок. Каждый из них передаст результат, который он не обработает, своим преемникам, и вместе они обработают как результат значения, так и результат ошибки. У этого есть дополнительное преимущество — catchError обрабатывает ошибки и в обработчике значения then также. Использование последовательных обработчиков вместо параллельных часто приводит к более легко разбираемому коду. Это также делает асинхронный код очень похожим на синхронный код:
// Synchronous code.
try {
int value = foo();
return bar(value);
} catch (e) {
return 499;
} Эквивалентный асинхронный код, основанный на объектах Future:
Future<int> asyncValue = Future(foo); // Result of foo() as a future.
asyncValue.then((int value) {
return bar(value);
}).catchError((e) {
return 499;
}); Подобно синхронному коду, обработчик ошибок (зарегистрированный с помощью catchError) обрабатывает любые ошибки, выброшенные либо foo, либо bar. Если бы обработчик ошибок был зарегистрирован как параметр onError вызова then, он не поймал бы ошибки из вызова bar.
Объект Future может иметь более одной пары обработчиков. Каждый преемник обрабатывается независимо и рассматривается так, как если бы он был единственным преемником.
Объект Future также может не завершиться. В этом случае никакие обработчики не вызываются. Такую ситуацию, если возможно, следует избегать, если это не явно документировано.
- Доступные расширения
Конструкторы
- Future(FutureOr<
T> computation()) factory - Создаёт объект Future, содержащий результат вызова
computationасинхронно с помощью Timer.run. - Future.delayed(Duration duration, [FutureOr<
T> computation()?]) factory - Создаёт объект Future, который выполняет вычисление после задержки.
- Future.error(Object error, [StackTrace? stackTrace]) factory
- Создаёт объект Future, завершающийся ошибкой.
- Future.microtask(FutureOr<
T> computation()) factory - Создаёт объект Future, содержащий результат вызова
computationасинхронно с помощью scheduleMicrotask. - Future.sync(FutureOr<
T> computation()) factory - Возвращает объект Future, содержащий результат немедленного вызова
computation. - Future.value([FutureOr<
T>? value]) factory - Создаёт объект Future, завершённый значением
value.
Свойства экземпляра
- hashCode → int только для чтения, унаследованное
- Код хэширования для этого объекта.
- runtimeType → Type только для чтения, унаследованное
- Представление типа объекта в ходе выполнения.
Методы экземпляра
- asStream(
) → Stream< T> - Создаёт Stream, содержащий результат этого объекта Future.
- catchError(
Function onError, {bool test(Object error)?}) → Future< T> - Обрабатывает ошибки, выпущенные этим объектом Future.
- noSuchMethod(
Invocation invocation) → dynamic унаследованное - Вызывается при обращении к несуществующему методу или свойству.
- then<
R>( FutureOr< R> onValue(T value), {Function? onError}) → Future< R> - Регистрирует обработчики, которые вызываются при завершении этого объекта Future.
- timeout(
Duration timeLimit, {FutureOr< T> onTimeout()?}) → Future< T> - Отключает вычисление объекта Future после истечения
timeLimit. - toString(
) → String унаследованное - Строковое представление этого объекта.
- whenComplete(
FutureOr< void> action()) → Future< T> - Регистрирует функцию, которая вызывается при завершении этого объекта Future.
Операторы
- operator ==(
Object other) → bool унаследованное - Оператор равенства.
Статические методы
- any<
T>( Iterable< Future< T>> futures) → Future< T> - Возвращает результат первого завершенного фьючера в
futures. - doWhile(
FutureOr< bool> action()) → Future - Повторяет операцию до тех пор, пока она не вернёт
false. - forEach<
T>( Iterable< T> elements, FutureOr action(T element)) → Future - Выполняет действие для каждого элемента в итерируемом объекте поочерёдно.
- wait<
T>( Iterable< Future< T>> futures, {bool eagerError = false, void cleanUp(T successValue)?}) → Future< List< T>> - Ожидает завершения нескольких фьючеров и собирает их результаты.
© 2012 the Dart project authors
Licensed under the BSD 3-Clause "New" or "Revised" License.
https://api.dart.dev/stable/2.18.5/dart-async/Future-class.html