wait< T> статический метод
Ожидает завершения нескольких futures и собирает их результаты.
Возвращает future, который завершится после завершения всех переданных futures: либо с их результатами, либо с ошибкой, если какой-либо из переданных futures завершится ошибкой.
Значением возвращённого future будет список всех значений, полученных в порядке, в котором они предоставляются при переборе futures.
Если какой-либо future завершится ошибкой, возвращённый future завершится с этой ошибкой. Если другие futures также завершатся ошибками, эти ошибки будут отброшены.
Если eagerError имеет значение true, возвращённый future немедленно завершится ошибкой при первой ошибке одного из futures. В противном случае возвращённый future завершится только после завершения всех futures (всё равно с первой ошибкой; остальные ошибки будут молча отброшены).
В случае ошибки функция cleanUp (если она указана) вызывается для любого ненулевого результата успешно завершившихся futures. Это позволяет cleanUp ресурсы, которые иначе были бы потеряны (поскольку возвращённый future не предоставляет доступа к этим значениям). Функция 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.19.6/dart-async/Future/wait.html