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 построены на основе этих средств, и иногда имеет смысл использовать их напрямую. Некоторые вещи невозможно сделать, просто применяя 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(FutureOr<
T> computation(), [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> - Возвращает результат первого future из
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>> - Ожидает завершения нескольких future и собирает их результаты.
© 2012 the Dart project authors
Licensed under the BSD 3-Clause "New" or "Revised" License.
https://api.dart.dev/stable/2.19.6/dart-async/Future-class.html