| 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 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 * error to occur, the remaining errors are silently dropped). | 288 * error to occur, the remaining errors are silently dropped). |
| 289 * | 289 * |
| 290 * If [cleanUp] is provided, in the case of an error, any non-null result of | 290 * If [cleanUp] is provided, in the case of an error, any non-null result of |
| 291 * a successful future is passed to `cleanUp`, which can then release any | 291 * a successful future is passed to `cleanUp`, which can then release any |
| 292 * resources that the successful operation allocated. | 292 * resources that the successful operation allocated. |
| 293 * | 293 * |
| 294 * The call to `cleanUp` should not throw. If it does, the error will be an | 294 * The call to `cleanUp` should not throw. If it does, the error will be an |
| 295 * uncaught asynchronous error. | 295 * uncaught asynchronous error. |
| 296 */ | 296 */ |
| 297 static Future<List<T>> wait<T>(Iterable<Future<T>> futures, | 297 static Future<List<T>> wait<T>(Iterable<Future<T>> futures, |
| 298 {bool eagerError: false, | 298 {bool eagerError: false, void cleanUp(T successValue)}) { |
| 299 void cleanUp(T successValue)}) { | |
| 300 final _Future<List<T>> result = new _Future<List<T>>(); | 299 final _Future<List<T>> result = new _Future<List<T>>(); |
| 301 List<T> values; // Collects the values. Set to null on error. | 300 List<T> values; // Collects the values. Set to null on error. |
| 302 int remaining = 0; // How many futures are we waiting for. | 301 int remaining = 0; // How many futures are we waiting for. |
| 303 var error; // The first error from a future. | 302 var error; // The first error from a future. |
| 304 StackTrace stackTrace; // The stackTrace that came with the error. | 303 StackTrace stackTrace; // The stackTrace that came with the error. |
| 305 | 304 |
| 306 // Handle an error from any of the futures. | 305 // Handle an error from any of the futures. |
| 307 // TODO(jmesserly): use `void` return type once it can be inferred for the | 306 // TODO(jmesserly): use `void` return type once it can be inferred for the |
| 308 // `then` call below. | 307 // `then` call below. |
| 309 handleError(theError, theStackTrace) { | 308 handleError(theError, theStackTrace) { |
| 310 remaining--; | 309 remaining--; |
| 311 if (values != null) { | 310 if (values != null) { |
| 312 if (cleanUp != null) { | 311 if (cleanUp != null) { |
| 313 for (var value in values) { | 312 for (var value in values) { |
| 314 if (value != null) { | 313 if (value != null) { |
| 315 // Ensure errors from cleanUp are uncaught. | 314 // Ensure errors from cleanUp are uncaught. |
| 316 new Future.sync(() { cleanUp(value); }); | 315 new Future.sync(() { |
| 316 cleanUp(value); |
| 317 }); |
| 317 } | 318 } |
| 318 } | 319 } |
| 319 } | 320 } |
| 320 values = null; | 321 values = null; |
| 321 if (remaining == 0 || eagerError) { | 322 if (remaining == 0 || eagerError) { |
| 322 result._completeError(theError, theStackTrace); | 323 result._completeError(theError, theStackTrace); |
| 323 } else { | 324 } else { |
| 324 error = theError; | 325 error = theError; |
| 325 stackTrace = theStackTrace; | 326 stackTrace = theStackTrace; |
| 326 } | 327 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 337 future.then((T value) { | 338 future.then((T value) { |
| 338 remaining--; | 339 remaining--; |
| 339 if (values != null) { | 340 if (values != null) { |
| 340 values[pos] = value; | 341 values[pos] = value; |
| 341 if (remaining == 0) { | 342 if (remaining == 0) { |
| 342 result._completeWithValue(values); | 343 result._completeWithValue(values); |
| 343 } | 344 } |
| 344 } else { | 345 } else { |
| 345 if (cleanUp != null && value != null) { | 346 if (cleanUp != null && value != null) { |
| 346 // Ensure errors from cleanUp are uncaught. | 347 // Ensure errors from cleanUp are uncaught. |
| 347 new Future.sync(() { cleanUp(value); }); | 348 new Future.sync(() { |
| 349 cleanUp(value); |
| 350 }); |
| 348 } | 351 } |
| 349 if (remaining == 0 && !eagerError) { | 352 if (remaining == 0 && !eagerError) { |
| 350 result._completeError(error, stackTrace); | 353 result._completeError(error, stackTrace); |
| 351 } | 354 } |
| 352 } | 355 } |
| 353 }, onError: handleError); | 356 }, onError: handleError); |
| 354 // Increment the 'remaining' after the call to 'then'. | 357 // Increment the 'remaining' after the call to 'then'. |
| 355 // If that call throws, we don't expect any future callback from | 358 // If that call throws, we don't expect any future callback from |
| 356 // the future, and we also don't increment remaining. | 359 // the future, and we also don't increment remaining. |
| 357 remaining++; | 360 remaining++; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 }; | 402 }; |
| 400 var onError = (error, stack) { | 403 var onError = (error, stack) { |
| 401 if (!completer.isCompleted) completer.completeError(error, stack); | 404 if (!completer.isCompleted) completer.completeError(error, stack); |
| 402 }; | 405 }; |
| 403 for (var future in futures) { | 406 for (var future in futures) { |
| 404 future.then(onValue, onError: onError); | 407 future.then(onValue, onError: onError); |
| 405 } | 408 } |
| 406 return completer.future; | 409 return completer.future; |
| 407 } | 410 } |
| 408 | 411 |
| 409 | |
| 410 /** | 412 /** |
| 411 * Perform an async operation for each element of the iterable, in turn. | 413 * Perform an async operation for each element of the iterable, in turn. |
| 412 * | 414 * |
| 413 * Runs [f] for each element in [input] in order, moving to the next element | 415 * Runs [f] for each element in [input] in order, moving to the next element |
| 414 * only when the [Future] returned by [f] completes. Returns a [Future] that | 416 * only when the [Future] returned by [f] completes. Returns a [Future] that |
| 415 * completes when all elements have been processed. | 417 * completes when all elements have been processed. |
| 416 * | 418 * |
| 417 * The return values of all [Future]s are discarded. Any errors will cause the | 419 * The return values of all [Future]s are discarded. Any errors will cause the |
| 418 * iteration to stop and will be piped through the returned [Future]. | 420 * iteration to stop and will be piped through the returned [Future]. |
| 419 * | 421 * |
| (...skipping 23 matching lines...) Expand all Loading... |
| 443 * The [f] function must return either a `bool` value or a [Future] completing | 445 * The [f] function must return either a `bool` value or a [Future] completing |
| 444 * with a `bool` value. | 446 * with a `bool` value. |
| 445 */ | 447 */ |
| 446 static Future doWhile(f()) { | 448 static Future doWhile(f()) { |
| 447 _Future doneSignal = new _Future(); | 449 _Future doneSignal = new _Future(); |
| 448 var nextIteration; | 450 var nextIteration; |
| 449 // Bind this callback explicitly so that each iteration isn't bound in the | 451 // Bind this callback explicitly so that each iteration isn't bound in the |
| 450 // context of all the previous iterations' callbacks. | 452 // context of all the previous iterations' callbacks. |
| 451 nextIteration = Zone.current.bindUnaryCallback((bool keepGoing) { | 453 nextIteration = Zone.current.bindUnaryCallback((bool keepGoing) { |
| 452 if (keepGoing) { | 454 if (keepGoing) { |
| 453 new Future.sync(f).then(nextIteration, | 455 new Future.sync(f) |
| 454 onError: doneSignal._completeError); | 456 .then(nextIteration, onError: doneSignal._completeError); |
| 455 } else { | 457 } else { |
| 456 doneSignal._complete(null); | 458 doneSignal._complete(null); |
| 457 } | 459 } |
| 458 }, runGuarded: true); | 460 }, runGuarded: true); |
| 459 nextIteration(true); | 461 nextIteration(true); |
| 460 return doneSignal; | 462 return doneSignal; |
| 461 } | 463 } |
| 462 | 464 |
| 463 /** | 465 /** |
| 464 * Register callbacks to be called when this future completes. | 466 * Register callbacks to be called when this future completes. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 492 * the future returned by `then` will be completed with | 494 * the future returned by `then` will be completed with |
| 493 * the same result as the future returned by the callback. | 495 * the same result as the future returned by the callback. |
| 494 * | 496 * |
| 495 * If [onError] is not given, and this future completes with an error, | 497 * If [onError] is not given, and this future completes with an error, |
| 496 * the error is forwarded directly to the returned future. | 498 * the error is forwarded directly to the returned future. |
| 497 * | 499 * |
| 498 * In most cases, it is more readable to use [catchError] separately, possibly | 500 * In most cases, it is more readable to use [catchError] separately, possibly |
| 499 * with a `test` parameter, instead of handling both value and error in a | 501 * with a `test` parameter, instead of handling both value and error in a |
| 500 * single [then] call. | 502 * single [then] call. |
| 501 */ | 503 */ |
| 502 Future<S> then<S>(FutureOr<S> onValue(T value), { Function onError }); | 504 Future<S> then<S>(FutureOr<S> onValue(T value), {Function onError}); |
| 503 | 505 |
| 504 /** | 506 /** |
| 505 * Handles errors emitted by this [Future]. | 507 * Handles errors emitted by this [Future]. |
| 506 * | 508 * |
| 507 * This is the asynchronous equivalent of a "catch" block. | 509 * This is the asynchronous equivalent of a "catch" block. |
| 508 * | 510 * |
| 509 * Returns a new [Future] that will be completed with either the result of | 511 * Returns a new [Future] that will be completed with either the result of |
| 510 * this future or the result of calling the `onError` callback. | 512 * this future or the result of calling the `onError` callback. |
| 511 * | 513 * |
| 512 * If this future completes with a value, | 514 * If this future completes with a value, |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 553 * } | 555 * } |
| 554 * | 556 * |
| 555 */ | 557 */ |
| 556 // The `Function` below stands for one of two types: | 558 // The `Function` below stands for one of two types: |
| 557 // - (dynamic) -> FutureOr<T> | 559 // - (dynamic) -> FutureOr<T> |
| 558 // - (dynamic, StackTrace) -> FutureOr<T> | 560 // - (dynamic, StackTrace) -> FutureOr<T> |
| 559 // Given that there is a `test` function that is usually used to do an | 561 // Given that there is a `test` function that is usually used to do an |
| 560 // `isCheck` we should also expect functions that take a specific argument. | 562 // `isCheck` we should also expect functions that take a specific argument. |
| 561 // Note: making `catchError` return a `Future<T>` in non-strong mode could be | 563 // Note: making `catchError` return a `Future<T>` in non-strong mode could be |
| 562 // a breaking change. | 564 // a breaking change. |
| 563 Future<T> catchError(Function onError, | 565 Future<T> catchError(Function onError, {bool test(Object error)}); |
| 564 {bool test(Object error)}); | |
| 565 | 566 |
| 566 /** | 567 /** |
| 567 * Register a function to be called when this future completes. | 568 * Register a function to be called when this future completes. |
| 568 * | 569 * |
| 569 * The [action] function is called when this future completes, whether it | 570 * The [action] function is called when this future completes, whether it |
| 570 * does so with a value or with an error. | 571 * does so with a value or with an error. |
| 571 * | 572 * |
| 572 * This is the asynchronous equivalent of a "finally" block. | 573 * This is the asynchronous equivalent of a "finally" block. |
| 573 * | 574 * |
| 574 * The future returned by this call, `f`, will complete the same way | 575 * The future returned by this call, `f`, will complete the same way |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 684 * _completer.complete(result); | 685 * _completer.complete(result); |
| 685 * } | 686 * } |
| 686 * | 687 * |
| 687 * // If something goes wrong, call this. | 688 * // If something goes wrong, call this. |
| 688 * void _errorHappened(error) { | 689 * void _errorHappened(error) { |
| 689 * _completer.completeError(error); | 690 * _completer.completeError(error); |
| 690 * } | 691 * } |
| 691 * } | 692 * } |
| 692 */ | 693 */ |
| 693 abstract class Completer<T> { | 694 abstract class Completer<T> { |
| 694 | |
| 695 /** | 695 /** |
| 696 * Creates a new completer. | 696 * Creates a new completer. |
| 697 * | 697 * |
| 698 * The general workflow for creating a new future is to 1) create a | 698 * The general workflow for creating a new future is to 1) create a |
| 699 * new completer, 2) hand out its future, and, at a later point, 3) invoke | 699 * new completer, 2) hand out its future, and, at a later point, 3) invoke |
| 700 * either [complete] or [completeError]. | 700 * either [complete] or [completeError]. |
| 701 * | 701 * |
| 702 * The completer completes the future asynchronously. That means that | 702 * The completer completes the future asynchronously. That means that |
| 703 * callbacks registered on the future, are not called immediately when | 703 * callbacks registered on the future, are not called immediately when |
| 704 * [complete] or [completeError] is called. Instead the callbacks are | 704 * [complete] or [completeError] is called. Instead the callbacks are |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 819 AsyncError replacement = Zone.current.errorCallback(error, stackTrace); | 819 AsyncError replacement = Zone.current.errorCallback(error, stackTrace); |
| 820 if (replacement != null) { | 820 if (replacement != null) { |
| 821 error = _nonNullError(replacement.error); | 821 error = _nonNullError(replacement.error); |
| 822 stackTrace = replacement.stackTrace; | 822 stackTrace = replacement.stackTrace; |
| 823 } | 823 } |
| 824 result._completeError(error, stackTrace); | 824 result._completeError(error, stackTrace); |
| 825 } | 825 } |
| 826 | 826 |
| 827 /** Helper function that converts `null` to a [NullThrownError]. */ | 827 /** Helper function that converts `null` to a [NullThrownError]. */ |
| 828 Object _nonNullError(Object error) => error ?? new NullThrownError(); | 828 Object _nonNullError(Object error) => error ?? new NullThrownError(); |
| OLD | NEW |