Метод wait< T>
Ожидает завершения нескольких отложенных задач и собирает их результаты.
Возвращает отложенную задачу, которая завершится, когда все предоставленные отложенные задачи завершатся, либо со своими результатами, либо с ошибкой, если какая-либо из предоставленных отложенных задач завершится с ошибкой.
Значение возвращаемой отложенной задачи будет списком всех значений, полученных в порядке, в котором отложенные задачи предоставляются путем итерирования futures.
Если какая-либо отложенная задача завершается с ошибкой, то возвращаемая отложенная задача завершается с этой ошибкой. Если другие отложенные задачи также завершаются с ошибками, эти ошибки игнорируются.
Если eagerError равно true, возвращаемая отложенная задача завершается с ошибкой сразу при первой ошибке от одной из отложенных задач. В противном случае все отложенные задачи должны завершиться, прежде чем возвращаемая отложенная задача завершится (все равно с первой ошибкой; оставшиеся ошибки молча игнорируются).
В случае ошибки cleanUp (если предоставлено) вызывается для любого ненулевого результата успешных отложенных задач. Это позволяет cleanUp ресурсы, которые в противном случае были бы потеряны (поскольку возвращаемая отложенная задача не предоставляет доступа к этим значениям). Функция cleanUp не используется, если ошибки нет.
Вызов cleanUp не должен генерировать исключение. Если это произойдет, ошибка будет необработанной асинхронной ошибкой.
Пример:
void main() async {
var value = await Future.wait([delayedNumber(), delayedString()]);
print(value); // [2, result]
}
Future<int> delayedNumber() async {
await Future.delayed(const Duration(seconds: 2));
return 2;
}
Future<String> delayedString() async {
await Future.delayed(const Duration(seconds: 2));
return 'result';
} Реализация
@pragma("vm:recognized", "other")
static Future<List<T>> wait<T>(Iterable<Future<T>> futures,
{bool eagerError = false, void cleanUp(T successValue)?}) {
// This is a VM recognised method, and the _future variable is deliberately
// allocated in a specific slot in the closure context for stack unwinding.
final _Future<List<T>> _future = _Future<List<T>>();
List<T?>? values; // Collects the values. Set to null on error.
int remaining = 0; // How many futures are we waiting for.
late Object error; // The first error from a future.
late StackTrace stackTrace; // The stackTrace that came with the error.
// Handle an error from any of the futures.
void handleError(Object theError, StackTrace theStackTrace) {
remaining--;
List<T?>? valueList = values;
if (valueList != null) {
if (cleanUp != null) {
for (var value in valueList) {
if (value != null) {
// Ensure errors from cleanUp are uncaught.
T cleanUpValue = value;
new Future.sync(() {
cleanUp(cleanUpValue);
});
}
}
}
values = null;
if (remaining == 0 || eagerError) {
_future._completeError(theError, theStackTrace);
} else {
error = theError;
stackTrace = theStackTrace;
}
} else if (remaining == 0 && !eagerError) {
_future._completeError(error, stackTrace);
}
}
try {
// As each future completes, put its value into the corresponding
// position in the list of values.
for (var future in futures) {
int pos = remaining;
future.then((T value) {
remaining--;
List<T?>? valueList = values;
if (valueList != null) {
valueList[pos] = value;
if (remaining == 0) {
_future._completeWithValue(List<T>.from(valueList));
}
} else {
if (cleanUp != null && value != null) {
// Ensure errors from cleanUp are uncaught.
new Future.sync(() {
cleanUp(value);
});
}
if (remaining == 0 && !eagerError) {
// If eagerError is false, and valueList is null, then
// error and stackTrace have been set in handleError above.
_future._completeError(error, stackTrace);
}
}
}, onError: handleError);
// Increment the 'remaining' after the call to 'then'.
// If that call throws, we don't expect any future callback from
// the future, and we also don't increment remaining.
remaining++;
}
if (remaining == 0) {
return _future.._completeWithValue(<T>[]);
}
values = new List<T?>.filled(remaining, null);
} catch (e, st) {
// The error must have been thrown while iterating over the futures
// list, or while installing a callback handler on the future.
// This is a breach of the `Future` protocol, but we try to handle it
// gracefully.
if (remaining == 0 || eagerError) {
// Throw a new Future.error.
// Don't just call `_future._completeError` since that would propagate
// the error too eagerly, not giving the callers time to install
// error handlers.
// Also, don't use `_asyncCompleteError` since that one doesn't give
// zones the chance to intercept the error.
return new Future.error(e, st);
} else {
// Don't allocate a list for values, thus indicating that there was an
// error.
// Set error to the caught exception.
error = e;
stackTrace = st;
}
}
return _future;
}
© 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/wait.html