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 |