| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart.async; | 5 part of dart.async; |
| 6 | 6 |
| 7 /// A type representing values that are either `Future<T>` or `T`. | 7 /// A type representing values that are either `Future<T>` or `T`. |
| 8 /// | 8 /// |
| 9 /// This class declaration is a public stand-in for an internal | 9 /// This class declaration is a public stand-in for an internal |
| 10 /// future-or-value generic type. References to this class are resolved to the | 10 /// future-or-value generic type. References to this class are resolved to the |
| (...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 416 var onError = (error, stack) { | 416 var onError = (error, stack) { |
| 417 if (!completer.isCompleted) completer.completeError(error, stack); | 417 if (!completer.isCompleted) completer.completeError(error, stack); |
| 418 }; | 418 }; |
| 419 for (var future in futures) { | 419 for (var future in futures) { |
| 420 future.then(onValue, onError: onError); | 420 future.then(onValue, onError: onError); |
| 421 } | 421 } |
| 422 return completer.future; | 422 return completer.future; |
| 423 } | 423 } |
| 424 | 424 |
| 425 /** | 425 /** |
| 426 * Perform an async operation for each element of the iterable, in turn. | 426 * Perform an operation for each element of the iterable, in turn. |
| 427 * | 427 * |
| 428 * Runs [f] for each element in [input] in order, moving to the next element | 428 * The operation, [f], may be either synchronous or asynchronous. |
| 429 * only when the [Future] returned by [f] completes. Returns a [Future] that | |
| 430 * completes when all elements have been processed. | |
| 431 * | 429 * |
| 432 * The return values of all [Future]s are discarded. Any errors will cause the | 430 * Calls [f] with each element in [input] in order. |
| 433 * iteration to stop and will be piped through the returned [Future]. | 431 * If the call to [f] returns a `Future<T>`, the iteration waits |
| 432 * until the future is completed before moving to the next element. |
| 434 * | 433 * |
| 435 * If [f] returns a non-[Future], iteration continues immediately. Otherwise | 434 * Returns a [Future] that completes with `null` when all elements have been |
| 436 * it waits for the returned [Future] to complete. | 435 * processed. |
| 436 * |
| 437 * Non-[Future] return values, and completion-values of returned [Future]s, |
| 438 * are discarded. |
| 439 * |
| 440 * Any error from [f], synchronous or asynchronous, will stop the iteration |
| 441 * and will be reported in the returned [Future]. |
| 437 */ | 442 */ |
| 438 static Future forEach<T>(Iterable<T> input, FutureOr f(T element)) { | 443 static Future forEach<T>(Iterable<T> input, FutureOr f(T element)) { |
| 439 var iterator = input.iterator; | 444 var iterator = input.iterator; |
| 440 return doWhile(() { | 445 return doWhile(() { |
| 441 if (!iterator.moveNext()) return false; | 446 if (!iterator.moveNext()) return false; |
| 442 return new Future.sync(() => f(iterator.current)).then((_) => true); | 447 var result = f(iterator.current); |
| 448 if (result is Future<T>) return result.then(_kTrue); |
| 449 return true; |
| 443 }); | 450 }); |
| 444 } | 451 } |
| 445 | 452 |
| 453 // Constant `true` function, used as callback by [forEach]. |
| 454 static bool _kTrue(_) => true; |
| 455 |
| 446 /** | 456 /** |
| 447 * Performs an async operation repeatedly until it returns `false`. | 457 * Performs an operation repeatedly until it returns `false`. |
| 448 * | 458 * |
| 449 * The function [f] is called repeatedly while it returns either the [bool] | 459 * The operation, [f], may be either synchronous or asynchronous. |
| 450 * value `true` or a [Future] which completes with the value `true`. | 460 * |
| 461 * The operation is called repeatedly as long as it returns either the [bool] |
| 462 * value `true` or a `Future<bool>` which completes with the value `true`. |
| 451 * | 463 * |
| 452 * If a call to [f] returns `false` or a [Future] that completes to `false`, | 464 * If a call to [f] returns `false` or a [Future] that completes to `false`, |
| 453 * iteration ends and the future returned by [doWhile] is completed with | 465 * iteration ends and the future returned by [doWhile] is completed with |
| 454 * a `null` value. | 466 * a `null` value. |
| 455 * | 467 * |
| 456 * If a call to [f] throws or a future returned by [f] completes with | 468 * If a call to [f] throws or a future returned by [f] completes with |
| 457 * an error, iteration ends and the future returned by [doWhile] | 469 * an error, iteration ends and the future returned by [doWhile] |
| 458 * completes with the same error. | 470 * completes with the same error. |
| 471 * |
| 472 * Calls to [f] may happen at any time, including immediately after calling |
| 473 * `doWhile`. The only restriction is a new call to [f] won't happen before |
| 474 * the previous call has returned, and if it returned a `Future<bool>`, not |
| 475 * until that future has completed. |
| 459 */ | 476 */ |
| 460 static Future doWhile(FutureOr<bool> f()) { | 477 static Future doWhile(FutureOr<bool> f()) { |
| 461 _Future doneSignal = new _Future(); | 478 _Future doneSignal = new _Future(); |
| 462 var nextIteration; | 479 var nextIteration; |
| 463 // Bind this callback explicitly so that each iteration isn't bound in the | 480 // Bind this callback explicitly so that each iteration isn't bound in the |
| 464 // context of all the previous iterations' callbacks. | 481 // context of all the previous iterations' callbacks. |
| 465 nextIteration = Zone.current.bindUnaryCallback((bool keepGoing) { | 482 nextIteration = Zone.current.bindUnaryCallback((bool keepGoing) { |
| 466 if (keepGoing) { | 483 if (keepGoing) { |
| 467 new Future.sync(f) | 484 FutureOr<bool> result; |
| 468 .then(nextIteration, onError: doneSignal._completeError); | 485 try { |
| 486 result = f(); |
| 487 } catch (error, stackTrace) { |
| 488 _completeWithErrorCallback(doneSignal, error, stackTrace); |
| 489 return; |
| 490 } |
| 491 if (result is Future<bool>) { |
| 492 result.then(nextIteration, onError: doneSignal._completeError); |
| 493 return; |
| 494 } |
| 495 nextIteration(result); |
| 469 } else { | 496 } else { |
| 470 doneSignal._complete(null); | 497 doneSignal._complete(null); |
| 471 } | 498 } |
| 472 }, runGuarded: true); | 499 }, runGuarded: true); |
| 473 nextIteration(true); | 500 nextIteration(true); |
| 474 return doneSignal; | 501 return doneSignal; |
| 475 } | 502 } |
| 476 | 503 |
| 477 /** | 504 /** |
| 478 * Register callbacks to be called when this future completes. | 505 * Register callbacks to be called when this future completes. |
| (...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 841 AsyncError replacement = Zone.current.errorCallback(error, stackTrace); | 868 AsyncError replacement = Zone.current.errorCallback(error, stackTrace); |
| 842 if (replacement != null) { | 869 if (replacement != null) { |
| 843 error = _nonNullError(replacement.error); | 870 error = _nonNullError(replacement.error); |
| 844 stackTrace = replacement.stackTrace; | 871 stackTrace = replacement.stackTrace; |
| 845 } | 872 } |
| 846 result._completeError(error, stackTrace); | 873 result._completeError(error, stackTrace); |
| 847 } | 874 } |
| 848 | 875 |
| 849 /** Helper function that converts `null` to a [NullThrownError]. */ | 876 /** Helper function that converts `null` to a [NullThrownError]. */ |
| 850 Object _nonNullError(Object error) => error ?? new NullThrownError(); | 877 Object _nonNullError(Object error) => error ?? new NullThrownError(); |
| OLD | NEW |