Spec-Zone.ru › Dart 2

dart:async

Метод wait<T>

Future<List<T>> wait<T>(
  1. Iterable<Future<T>> futures,
  2. {bool eagerError = false,
  3. void cleanUp(
    1. T successValue
    )?}
)

Ожидает завершения нескольких отложенных задач и собирает их результаты.

Возвращает отложенную задачу, которая завершится, когда все предоставленные отложенные задачи завершатся, либо со своими результатами, либо с ошибкой, если какая-либо из предоставленных отложенных задач завершится с ошибкой.

Значение возвращаемой отложенной задачи будет списком всех значений, полученных в порядке, в котором отложенные задачи предоставляются путем итерирования 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API