| 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 /** The onValue and onError handlers return either a value or a future */ | 7 /** The onValue and onError handlers return either a value or a future */ |
| 8 typedef dynamic _FutureOnValue<T>(T value); | 8 typedef dynamic _FutureOnValue<T>(T value); |
| 9 /** Test used by [Future.catchError] to handle skip some errors. */ | 9 /** Test used by [Future.catchError] to handle skip some errors. */ |
| 10 typedef bool _FutureErrorTest(var error); | 10 typedef bool _FutureErrorTest(var error); |
| 11 /** Used by [WhenFuture]. */ | 11 /** Used by [WhenFuture]. */ |
| 12 typedef _FutureAction(); | 12 typedef _FutureAction(); |
| 13 | 13 |
| 14 abstract class _Completer<T> implements Completer<T> { | 14 abstract class _Completer<T> implements Completer<T> { |
| 15 final _Future<T> future = new _Future<T>(); | 15 final _Future<T> future = new _Future<T>(); |
| 16 | 16 |
| 17 void complete([value]); | 17 void complete([value]); |
| 18 | 18 |
| 19 void completeError(Object error, [StackTrace stackTrace]); | 19 void completeError(Object error, [StackTrace stackTrace]) { |
| 20 if (error == null) throw new ArgumentError("Error must not be null"); |
| 21 if (!future._mayComplete) throw new StateError("Future already completed"); |
| 22 AsyncError replacement = Zone.current.errorCallback(error, stackTrace); |
| 23 if (replacement != null) { |
| 24 error = replacement.error; |
| 25 stackTrace = replacement.stackTrace; |
| 26 } |
| 27 _completeError(error, stackTrace); |
| 28 } |
| 29 |
| 30 void _completeError(Object error, StackTrace stackTrace); |
| 20 | 31 |
| 21 // The future's _isComplete doesn't take into account pending completions. | 32 // The future's _isComplete doesn't take into account pending completions. |
| 22 // We therefore use _mayComplete. | 33 // We therefore use _mayComplete. |
| 23 bool get isCompleted => !future._mayComplete; | 34 bool get isCompleted => !future._mayComplete; |
| 24 } | 35 } |
| 25 | 36 |
| 26 class _AsyncCompleter<T> extends _Completer<T> { | 37 class _AsyncCompleter<T> extends _Completer<T> { |
| 27 | 38 |
| 28 void complete([value]) { | 39 void complete([value]) { |
| 29 if (!future._mayComplete) throw new StateError("Future already completed"); | 40 if (!future._mayComplete) throw new StateError("Future already completed"); |
| 30 future._asyncComplete(value); | 41 future._asyncComplete(value); |
| 31 } | 42 } |
| 32 | 43 |
| 33 void completeError(Object error, [StackTrace stackTrace]) { | 44 void _completeError(Object error, StackTrace stackTrace) { |
| 34 if (error == null) throw new ArgumentError("Error must not be null"); | |
| 35 if (!future._mayComplete) throw new StateError("Future already completed"); | |
| 36 future._asyncCompleteError(error, stackTrace); | 45 future._asyncCompleteError(error, stackTrace); |
| 37 } | 46 } |
| 38 } | 47 } |
| 39 | 48 |
| 40 class _SyncCompleter<T> extends _Completer<T> { | 49 class _SyncCompleter<T> extends _Completer<T> { |
| 41 | 50 |
| 42 void complete([value]) { | 51 void complete([value]) { |
| 43 if (!future._mayComplete) throw new StateError("Future already completed"); | 52 if (!future._mayComplete) throw new StateError("Future already completed"); |
| 44 future._complete(value); | 53 future._complete(value); |
| 45 } | 54 } |
| 46 | 55 |
| 47 void completeError(Object error, [StackTrace stackTrace]) { | 56 void _completeError(Object error, StackTrace stackTrace) { |
| 48 if (!future._mayComplete) throw new StateError("Future already completed"); | |
| 49 future._completeError(error, stackTrace); | 57 future._completeError(error, stackTrace); |
| 50 } | 58 } |
| 51 } | 59 } |
| 52 | 60 |
| 53 class _Future<T> implements Future<T> { | 61 class _Future<T> implements Future<T> { |
| 54 // State of the future. The state determines the interpretation of the | 62 // State of the future. The state determines the interpretation of the |
| 55 // [resultOrListeners] field. | 63 // [resultOrListeners] field. |
| 56 // TODO(lrn): rename field since it can also contain a chained future. | 64 // TODO(lrn): rename field since it can also contain a chained future. |
| 57 | 65 |
| 58 /// Initial state, waiting for a result. In this state, the | 66 /// Initial state, waiting for a result. In this state, the |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 void _markPendingCompletion() { | 214 void _markPendingCompletion() { |
| 207 if (!_mayComplete) throw new StateError("Future already completed"); | 215 if (!_mayComplete) throw new StateError("Future already completed"); |
| 208 _state = _PENDING_COMPLETE; | 216 _state = _PENDING_COMPLETE; |
| 209 } | 217 } |
| 210 | 218 |
| 211 T get _value { | 219 T get _value { |
| 212 assert(_isComplete && _hasValue); | 220 assert(_isComplete && _hasValue); |
| 213 return _resultOrListeners; | 221 return _resultOrListeners; |
| 214 } | 222 } |
| 215 | 223 |
| 216 _AsyncError get _error { | 224 AsyncError get _error { |
| 217 assert(_isComplete && _hasError); | 225 assert(_isComplete && _hasError); |
| 218 return _resultOrListeners; | 226 return _resultOrListeners; |
| 219 } | 227 } |
| 220 | 228 |
| 221 void _setValue(T value) { | 229 void _setValue(T value) { |
| 222 assert(!_isComplete); // But may have a completion pending. | 230 assert(!_isComplete); // But may have a completion pending. |
| 223 _state = _VALUE; | 231 _state = _VALUE; |
| 224 _resultOrListeners = value; | 232 _resultOrListeners = value; |
| 225 } | 233 } |
| 226 | 234 |
| 227 void _setError(Object error, StackTrace stackTrace) { | 235 void _setError(Object error, StackTrace stackTrace) { |
| 228 assert(!_isComplete); // But may have a completion pending. | 236 assert(!_isComplete); // But may have a completion pending. |
| 229 _state = _ERROR; | 237 _state = _ERROR; |
| 230 _resultOrListeners = new _AsyncError(error, stackTrace); | 238 _resultOrListeners = new AsyncError(error, stackTrace); |
| 231 } | 239 } |
| 232 | 240 |
| 233 void _addListener(_Future listener) { | 241 void _addListener(_Future listener) { |
| 234 assert(listener._nextListener == null); | 242 assert(listener._nextListener == null); |
| 235 if (_isComplete) { | 243 if (_isComplete) { |
| 236 // Handle late listeners asynchronously. | 244 // Handle late listeners asynchronously. |
| 237 _zone.scheduleMicrotask(() { | 245 _zone.scheduleMicrotask(() { |
| 238 _propagateToListeners(this, listener); | 246 _propagateToListeners(this, listener); |
| 239 }); | 247 }); |
| 240 } else { | 248 } else { |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 * | 438 * |
| 431 * If [runCallback] is true (which should be the default) it executes | 439 * If [runCallback] is true (which should be the default) it executes |
| 432 * the registered action of listeners. If it is `false` then the callback is | 440 * the registered action of listeners. If it is `false` then the callback is |
| 433 * skipped. This is used to complete futures with chained futures. | 441 * skipped. This is used to complete futures with chained futures. |
| 434 */ | 442 */ |
| 435 static void _propagateToListeners(_Future source, _Future listeners) { | 443 static void _propagateToListeners(_Future source, _Future listeners) { |
| 436 while (true) { | 444 while (true) { |
| 437 if (!source._isComplete) return; // Chained future. | 445 if (!source._isComplete) return; // Chained future. |
| 438 bool hasError = source._hasError; | 446 bool hasError = source._hasError; |
| 439 if (hasError && listeners == null) { | 447 if (hasError && listeners == null) { |
| 440 _AsyncError asyncError = source._error; | 448 AsyncError asyncError = source._error; |
| 441 source._zone.handleUncaughtError( | 449 source._zone.handleUncaughtError( |
| 442 asyncError.error, asyncError.stackTrace); | 450 asyncError.error, asyncError.stackTrace); |
| 443 return; | 451 return; |
| 444 } | 452 } |
| 445 if (listeners == null) return; | 453 if (listeners == null) return; |
| 446 _Future listener = listeners; | 454 _Future listener = listeners; |
| 447 if (listener._nextListener != null) { | 455 if (listener._nextListener != null) { |
| 448 // Usually futures only have one listener. If they have several, we | 456 // Usually futures only have one listener. If they have several, we |
| 449 // handle them specially. | 457 // handle them specially. |
| 450 _propagateMultipleListeners(source, listeners); | 458 _propagateMultipleListeners(source, listeners); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 464 // the future is not already marked (or chained). | 472 // the future is not already marked (or chained). |
| 465 // Only if we either have an error or callbacks, go into this, somewhat | 473 // Only if we either have an error or callbacks, go into this, somewhat |
| 466 // expensive, branch. Here we'll enter/leave the zone. Many futures | 474 // expensive, branch. Here we'll enter/leave the zone. Many futures |
| 467 // doesn't have callbacks, so this is a significant optimization. | 475 // doesn't have callbacks, so this is a significant optimization. |
| 468 if (hasError || | 476 if (hasError || |
| 469 listener._onValue != null || | 477 listener._onValue != null || |
| 470 listener._whenCompleteAction != null) { | 478 listener._whenCompleteAction != null) { |
| 471 Zone zone = listener._zone; | 479 Zone zone = listener._zone; |
| 472 if (hasError && !source._zone.inSameErrorZone(zone)) { | 480 if (hasError && !source._zone.inSameErrorZone(zone)) { |
| 473 // Don't cross zone boundaries with errors. | 481 // Don't cross zone boundaries with errors. |
| 474 _AsyncError asyncError = source._error; | 482 AsyncError asyncError = source._error; |
| 475 source._zone.handleUncaughtError( | 483 source._zone.handleUncaughtError( |
| 476 asyncError.error, asyncError.stackTrace); | 484 asyncError.error, asyncError.stackTrace); |
| 477 return; | 485 return; |
| 478 } | 486 } |
| 479 | 487 |
| 480 Zone oldZone; | 488 Zone oldZone; |
| 481 if (!identical(Zone.current, zone)) { | 489 if (!identical(Zone.current, zone)) { |
| 482 // Change zone if it's not current. | 490 // Change zone if it's not current. |
| 483 oldZone = Zone._enter(zone); | 491 oldZone = Zone._enter(zone); |
| 484 } | 492 } |
| 485 | 493 |
| 486 bool handleValueCallback() { | 494 bool handleValueCallback() { |
| 487 try { | 495 try { |
| 488 listenerValueOrError = zone.runUnary(listener._onValue, | 496 listenerValueOrError = zone.runUnary(listener._onValue, |
| 489 sourceValue); | 497 sourceValue); |
| 490 return true; | 498 return true; |
| 491 } catch (e, s) { | 499 } catch (e, s) { |
| 492 listenerValueOrError = new _AsyncError(e, s); | 500 listenerValueOrError = new AsyncError(e, s); |
| 493 return false; | 501 return false; |
| 494 } | 502 } |
| 495 } | 503 } |
| 496 | 504 |
| 497 void handleError() { | 505 void handleError() { |
| 498 _AsyncError asyncError = source._error; | 506 AsyncError asyncError = source._error; |
| 499 _FutureErrorTest test = listener._errorTest; | 507 _FutureErrorTest test = listener._errorTest; |
| 500 bool matchesTest = true; | 508 bool matchesTest = true; |
| 501 if (test != null) { | 509 if (test != null) { |
| 502 try { | 510 try { |
| 503 matchesTest = zone.runUnary(test, asyncError.error); | 511 matchesTest = zone.runUnary(test, asyncError.error); |
| 504 } catch (e, s) { | 512 } catch (e, s) { |
| 505 // TODO(ajohnsen): Should we suport rethrow for test throws? | 513 // TODO(ajohnsen): Should we suport rethrow for test throws? |
| 506 listenerValueOrError = identical(asyncError.error, e) ? | 514 listenerValueOrError = identical(asyncError.error, e) ? |
| 507 asyncError : new _AsyncError(e, s); | 515 asyncError : new AsyncError(e, s); |
| 508 listenerHasValue = false; | 516 listenerHasValue = false; |
| 509 return; | 517 return; |
| 510 } | 518 } |
| 511 } | 519 } |
| 512 Function errorCallback = listener._onError; | 520 Function errorCallback = listener._onError; |
| 513 if (matchesTest && errorCallback != null) { | 521 if (matchesTest && errorCallback != null) { |
| 514 try { | 522 try { |
| 515 if (errorCallback is ZoneBinaryCallback) { | 523 if (errorCallback is ZoneBinaryCallback) { |
| 516 listenerValueOrError = zone.runBinary(errorCallback, | 524 listenerValueOrError = zone.runBinary(errorCallback, |
| 517 asyncError.error, | 525 asyncError.error, |
| 518 asyncError.stackTrace); | 526 asyncError.stackTrace); |
| 519 } else { | 527 } else { |
| 520 listenerValueOrError = zone.runUnary(errorCallback, | 528 listenerValueOrError = zone.runUnary(errorCallback, |
| 521 asyncError.error); | 529 asyncError.error); |
| 522 } | 530 } |
| 523 } catch (e, s) { | 531 } catch (e, s) { |
| 524 listenerValueOrError = identical(asyncError.error, e) ? | 532 listenerValueOrError = identical(asyncError.error, e) ? |
| 525 asyncError : new _AsyncError(e, s); | 533 asyncError : new AsyncError(e, s); |
| 526 listenerHasValue = false; | 534 listenerHasValue = false; |
| 527 return; | 535 return; |
| 528 } | 536 } |
| 529 listenerHasValue = true; | 537 listenerHasValue = true; |
| 530 } else { | 538 } else { |
| 531 // Copy over the error from the source. | 539 // Copy over the error from the source. |
| 532 listenerValueOrError = asyncError; | 540 listenerValueOrError = asyncError; |
| 533 listenerHasValue = false; | 541 listenerHasValue = false; |
| 534 } | 542 } |
| 535 } | 543 } |
| 536 | 544 |
| 537 void handleWhenCompleteCallback() { | 545 void handleWhenCompleteCallback() { |
| 538 var completeResult; | 546 var completeResult; |
| 539 try { | 547 try { |
| 540 completeResult = zone.run(listener._whenCompleteAction); | 548 completeResult = zone.run(listener._whenCompleteAction); |
| 541 } catch (e, s) { | 549 } catch (e, s) { |
| 542 if (hasError && identical(source._error.error, e)) { | 550 if (hasError && identical(source._error.error, e)) { |
| 543 listenerValueOrError = source._error; | 551 listenerValueOrError = source._error; |
| 544 } else { | 552 } else { |
| 545 listenerValueOrError = new _AsyncError(e, s); | 553 listenerValueOrError = new AsyncError(e, s); |
| 546 } | 554 } |
| 547 listenerHasValue = false; | 555 listenerHasValue = false; |
| 548 } | 556 } |
| 549 if (completeResult is Future) { | 557 if (completeResult is Future) { |
| 550 listener._isChained = true; | 558 listener._isChained = true; |
| 551 isPropagationAborted = true; | 559 isPropagationAborted = true; |
| 552 completeResult.then((ignored) { | 560 completeResult.then((ignored) { |
| 553 // Try again. Since the future is marked as chained it won't run | 561 // Try again. Since the future is marked as chained it won't run |
| 554 // the whenComplete again. | 562 // the whenComplete again. |
| 555 _propagateToListeners(source, listener); | 563 _propagateToListeners(source, listener); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 607 _chainForeignFuture(chainSource, listener); | 615 _chainForeignFuture(chainSource, listener); |
| 608 } | 616 } |
| 609 return; | 617 return; |
| 610 } | 618 } |
| 611 } | 619 } |
| 612 if (listenerHasValue) { | 620 if (listenerHasValue) { |
| 613 listeners = listener._removeListeners(); | 621 listeners = listener._removeListeners(); |
| 614 listener._setValue(listenerValueOrError); | 622 listener._setValue(listenerValueOrError); |
| 615 } else { | 623 } else { |
| 616 listeners = listener._removeListeners(); | 624 listeners = listener._removeListeners(); |
| 617 _AsyncError asyncError = listenerValueOrError; | 625 AsyncError asyncError = listenerValueOrError; |
| 618 listener._setError(asyncError.error, asyncError.stackTrace); | 626 listener._setError(asyncError.error, asyncError.stackTrace); |
| 619 } | 627 } |
| 620 // Prepare for next round. | 628 // Prepare for next round. |
| 621 source = listener; | 629 source = listener; |
| 622 } | 630 } |
| 623 } | 631 } |
| 624 | 632 |
| 625 Future timeout(Duration timeLimit, {onTimeout()}) { | 633 Future timeout(Duration timeLimit, {onTimeout()}) { |
| 626 if (_isComplete) return new _Future.immediate(this); | 634 if (_isComplete) return new _Future.immediate(this); |
| 627 _Future result = new _Future(); | 635 _Future result = new _Future(); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 649 } | 657 } |
| 650 }, onError: (e, s) { | 658 }, onError: (e, s) { |
| 651 if (timer.isActive) { | 659 if (timer.isActive) { |
| 652 timer.cancel(); | 660 timer.cancel(); |
| 653 result._completeError(e, s); | 661 result._completeError(e, s); |
| 654 } | 662 } |
| 655 }); | 663 }); |
| 656 return result; | 664 return result; |
| 657 } | 665 } |
| 658 } | 666 } |
| OLD | NEW |