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 |