| 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 const bool _GUARDED = true; |  | 
|   15 const bool _UNGUARDED = false; |  | 
|   16  |  | 
|   17 abstract class _Completer<T> implements Completer<T> { |   14 abstract class _Completer<T> implements Completer<T> { | 
|   18   final _Future<T> future = new _Future<T>(); |   15   final _Future<T> future = new _Future<T>(); | 
|   19  |   16  | 
|   20   void complete([value]); |   17   void complete([value]); | 
|   21  |   18  | 
|   22   void completeError(Object error, [StackTrace stackTrace]) { |   19   void completeError(Object error, [StackTrace stackTrace]) { | 
|   23     error = _nonNullError(error); |   20     error = _nonNullError(error); | 
|   24     if (!future._mayComplete) throw new StateError("Future already completed"); |   21     if (!future._mayComplete) throw new StateError("Future already completed"); | 
|   25     AsyncError replacement = Zone.current.errorCallback(error, stackTrace); |   22     AsyncError replacement = Zone.current.errorCallback(error, stackTrace); | 
|   26     if (replacement != null) { |   23     if (replacement != null) { | 
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  267  |  264  | 
|  268   void _setError(Object error, StackTrace stackTrace) { |  265   void _setError(Object error, StackTrace stackTrace) { | 
|  269     _setErrorObject(new AsyncError(error, stackTrace)); |  266     _setErrorObject(new AsyncError(error, stackTrace)); | 
|  270   } |  267   } | 
|  271  |  268  | 
|  272   void _addListener(_FutureListener listener) { |  269   void _addListener(_FutureListener listener) { | 
|  273     assert(listener._nextListener == null); |  270     assert(listener._nextListener == null); | 
|  274     if (_isComplete) { |  271     if (_isComplete) { | 
|  275       // Handle late listeners asynchronously. |  272       // Handle late listeners asynchronously. | 
|  276       _zone.scheduleMicrotask(() { |  273       _zone.scheduleMicrotask(() { | 
|  277         _propagateToFutures(this, listener, _UNGUARDED); |  274         _propagateToListeners(this, listener); | 
|  278       }); |  275       }); | 
|  279     } else { |  276     } else { | 
|  280       listener._nextListener = _resultOrListeners; |  277       listener._nextListener = _resultOrListeners; | 
|  281       _resultOrListeners = listener; |  278       _resultOrListeners = listener; | 
|  282     } |  279     } | 
|  283   } |  280   } | 
|  284  |  281  | 
|  285   _FutureListener _removeListeners() { |  282   _FutureListener _removeListeners() { | 
|  286     // Reverse listeners before returning them, so the resulting list is in |  283     // Reverse listeners before returning them, so the resulting list is in | 
|  287     // subscription order. |  284     // subscription order. | 
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  324   // Take the value (when completed) of source and complete target with that |  321   // Take the value (when completed) of source and complete target with that | 
|  325   // value (or error). This function expects that source is a _Future. |  322   // value (or error). This function expects that source is a _Future. | 
|  326   static void _chainCoreFuture(_Future source, _Future target) { |  323   static void _chainCoreFuture(_Future source, _Future target) { | 
|  327     assert(!target._isComplete); |  324     assert(!target._isComplete); | 
|  328     assert(source is _Future); |  325     assert(source is _Future); | 
|  329  |  326  | 
|  330     // Mark the target as chained (and as such half-completed). |  327     // Mark the target as chained (and as such half-completed). | 
|  331     target._isChained = true; |  328     target._isChained = true; | 
|  332     _FutureListener listener = new _FutureListener.chain(target); |  329     _FutureListener listener = new _FutureListener.chain(target); | 
|  333     if (source._isComplete) { |  330     if (source._isComplete) { | 
|  334       _propagateToFutures(source, listener, _GUARDED); |  331       _propagateToListeners(source, listener); | 
|  335     } else { |  332     } else { | 
|  336       source._addListener(listener); |  333       source._addListener(listener); | 
|  337     } |  334     } | 
|  338   } |  335   } | 
|  339  |  336  | 
|  340   void _complete(value) { |  337   void _complete(value) { | 
|  341     assert(!_isComplete); |  338     assert(!_isComplete); | 
|  342     if (value is Future) { |  339     if (value is Future) { | 
|  343       if (value is _Future) { |  340       if (value is _Future) { | 
|  344         _chainCoreFuture(value, this); |  341         _chainCoreFuture(value, this); | 
|  345       } else { |  342       } else { | 
|  346         _chainForeignFuture(value, this); |  343         _chainForeignFuture(value, this); | 
|  347       } |  344       } | 
|  348     } else { |  345     } else { | 
|  349       _FutureListener listeners = _removeListeners(); |  346       _FutureListener listeners = _removeListeners(); | 
|  350       _setValue(value); |  347       _setValue(value); | 
|  351       _propagateToFutures(this, listeners, _GUARDED); |  348       _propagateToListeners(this, listeners); | 
|  352     } |  349     } | 
|  353   } |  350   } | 
|  354  |  351  | 
|  355   void _completeWithValue(value) { |  352   void _completeWithValue(value) { | 
|  356     assert(!_isComplete); |  353     assert(!_isComplete); | 
|  357     assert(value is! Future); |  354     assert(value is! Future); | 
|  358  |  355  | 
|  359     _FutureListener listeners = _removeListeners(); |  356     _FutureListener listeners = _removeListeners(); | 
|  360     _setValue(value); |  357     _setValue(value); | 
|  361     _propagateToFutures(this, listeners, _GUARDED); |  358     _propagateToListeners(this, listeners); | 
|  362   } |  359   } | 
|  363  |  360  | 
|  364   void _completeError(error, [StackTrace stackTrace]) { |  361   void _completeError(error, [StackTrace stackTrace]) { | 
|  365     assert(!_isComplete); |  362     assert(!_isComplete); | 
|  366  |  363  | 
|  367     _FutureListener listeners = _removeListeners(); |  364     _FutureListener listeners = _removeListeners(); | 
|  368     _setError(error, stackTrace); |  365     _setError(error, stackTrace); | 
|  369     _propagateToFutures(this, listeners, _GUARDED); |  366     _propagateToListeners(this, listeners); | 
|  370   } |  367   } | 
|  371  |  368  | 
|  372   void _asyncComplete(value) { |  369   void _asyncComplete(value) { | 
|  373     assert(!_isComplete); |  370     assert(!_isComplete); | 
|  374     // Two corner cases if the value is a future: |  371     // Two corner cases if the value is a future: | 
|  375     //   1. the future is already completed and an error. |  372     //   1. the future is already completed and an error. | 
|  376     //   2. the future is not yet completed but might become an error. |  373     //   2. the future is not yet completed but might become an error. | 
|  377     // The first case means that we must not immediately complete the Future, |  374     // The first case means that we must not immediately complete the Future, | 
|  378     // as our code would immediately start propagating the error without |  375     // as our code would immediately start propagating the error without | 
|  379     // giving the time to install error-handlers. |  376     // giving the time to install error-handlers. | 
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  419   void _asyncCompleteError(error, StackTrace stackTrace) { |  416   void _asyncCompleteError(error, StackTrace stackTrace) { | 
|  420     assert(!_isComplete); |  417     assert(!_isComplete); | 
|  421  |  418  | 
|  422     _markPendingCompletion(); |  419     _markPendingCompletion(); | 
|  423     _zone.scheduleMicrotask(() { |  420     _zone.scheduleMicrotask(() { | 
|  424       _completeError(error, stackTrace); |  421       _completeError(error, stackTrace); | 
|  425     }); |  422     }); | 
|  426   } |  423   } | 
|  427  |  424  | 
|  428   /** |  425   /** | 
|  429    * Stack implemented by linked list of [_PendingFutureListeners]. |  | 
|  430    * |  | 
|  431    * Each `_PendingFutureListeners` have on source future and one or more |  | 
|  432    * listeners on that future (linked internally through |  | 
|  433    * [_FutureListener._nextListener]). |  | 
|  434    * |  | 
|  435    * While propagating future results to listeners, pending listeners are |  | 
|  436    * stored on this stack. |  | 
|  437    */ |  | 
|  438   static _PendingFutureListeners _pendingFutureListeners = null; |  | 
|  439  |  | 
|  440   /** |  | 
|  441    * Handle an uncaught async error. |  | 
|  442    * |  | 
|  443    * If the [guarded] flag is `true`, or the future's zone has an error |  | 
|  444    * handler, the uncaught error is passed to the zone's error handler. |  | 
|  445    * Otherwise, the uncaught error is thrown immediately, and is expected |  | 
|  446    * to propagate to the event loop. (If it can't propagate to the event |  | 
|  447    * loop, `guarded` should be true). |  | 
|  448    */ |  | 
|  449   static void _throwUncaughtError(_Future source, bool guarded) { |  | 
|  450     assert(source._hasError); |  | 
|  451     AsyncError asyncError = source._error; |  | 
|  452     Zone zone = source._zone; |  | 
|  453     if (guarded || !identical(zone.errorZone, _ROOT_ZONE)) { |  | 
|  454       zone.handleUncaughtError(asyncError.error, asyncError.stackTrace); |  | 
|  455       if (_pendingFutureListeners != null) { |  | 
|  456         _schedulePriorityAsyncCallback(_propagateToFutures); |  | 
|  457       } |  | 
|  458       return; |  | 
|  459     } |  | 
|  460     if (_pendingFutureListeners != null) { |  | 
|  461       _schedulePriorityAsyncCallback(_propagateToFutures); |  | 
|  462     } |  | 
|  463     throw new _UncaughtAsyncError(asyncError.error, asyncError.stackTrace); |  | 
|  464   } |  | 
|  465  |  | 
|  466   /** |  | 
|  467    * Propagates the value/error of [source] to its [listeners], executing the |  426    * Propagates the value/error of [source] to its [listeners], executing the | 
|  468    * listeners' callbacks. |  427    * listeners' callbacks. | 
|  469    * |  | 
|  470    * The [guarded] flag should be set when the function isn't being called in |  | 
|  471    * tail position of an event, or if simply throwing an uncaught error is |  | 
|  472    * otherwise not acceptable. |  | 
|  473    * |  | 
|  474    * Parameters are optional to allow using [_propagateToFutures] directly |  | 
|  475    * as a scheduled function. In that case, it takes its sources from |  | 
|  476    * [_pendingFutureListeners]. |  | 
|  477    */ |  428    */ | 
|  478   static void _propagateToFutures([_Future source, |  429   static void _propagateToListeners(_Future source, _FutureListener listeners) { | 
|  479                                    _FutureListener listeners, |  | 
|  480                                    bool guarded = _UNGUARDED]) { |  | 
|  481     while (true) { |  430     while (true) { | 
|  482       if (source == null) { |  431       assert(source._isComplete); | 
|  483         // Pop source and listeners from _pendingFutureListeners. |  432       bool hasError = source._hasError; | 
|  484         // This always sets `listeners` to be a single listener. |  433       if (listeners == null) { | 
|  485         if (_pendingFutureListeners == null) return; |  434         if (hasError) { | 
|  486         _PendingFutureListeners pending = _pendingFutureListeners; |  435           AsyncError asyncError = source._error; | 
|  487         // Read top-most source and listener. |  436           source._zone.handleUncaughtError( | 
|  488         source = pending.source; |  437               asyncError.error, asyncError.stackTrace); | 
|  489         listeners = pending.listeners; |  | 
|  490         // Remove the top-most listener. If it's the last listener for |  | 
|  491         // source, go to the next _PendingFutureListeners block. |  | 
|  492         if (listeners != null && listeners._nextListener != null) { |  | 
|  493           pending.listeners = listeners._nextListener; |  | 
|  494           listeners._nextListener = null; |  | 
|  495         } else { |  | 
|  496           _pendingFutureListeners = pending.next; |  | 
|  497         } |  438         } | 
|  498       } else { |  439         return; | 
|  499         // Check if there are zero listeners, or more than one listener. |  | 
|  500         assert(source._isComplete); |  | 
|  501         if (listeners == null) { |  | 
|  502           // If zero listeners, and source has an error, consider the error |  | 
|  503           // uncaught. |  | 
|  504           if (source._hasError) { |  | 
|  505             _throwUncaughtError(source, guarded); |  | 
|  506             return; |  | 
|  507           } |  | 
|  508           if (_pendingFutureListeners == null) return; |  | 
|  509           source = null; |  | 
|  510           continue; |  | 
|  511         } else if (listeners._nextListener != null) { |  | 
|  512           // Usually futures only have one listener. |  | 
|  513           // If they have several, we put the rest on the pending listener |  | 
|  514           // stack and handle them later. |  | 
|  515           _pendingFutureListeners = |  | 
|  516               new _PendingFutureListeners(source, listeners._nextListener, |  | 
|  517                                           _pendingFutureListeners); |  | 
|  518           listeners._nextListener = null; |  | 
|  519         } |  | 
|  520       } |  440       } | 
|  521       assert(source != null); |  441       // Usually futures only have one listener. If they have several, we | 
|  522       assert(listeners != null); |  442       // call handle them separately in recursive calls, continuing | 
|  523       assert(listeners._nextListener == null); |  443       // here only when there is only one listener left. | 
 |  444       while (listeners._nextListener != null) { | 
 |  445         _FutureListener listener = listeners; | 
 |  446         listeners = listener._nextListener; | 
 |  447         listener._nextListener = null; | 
 |  448         _propagateToListeners(source, listener); | 
 |  449       } | 
|  524       _FutureListener listener = listeners; |  450       _FutureListener listener = listeners; | 
|  525  |  | 
|  526       bool hasError = source._hasError; |  | 
|  527       // Do the actual propagation. |  451       // Do the actual propagation. | 
|  528       // Set initial state of listenerHasError and listenerValueOrError. These |  452       // Set initial state of listenerHasValue and listenerValueOrError. These | 
|  529       // variables are updated, with the outcome of potential callbacks. |  453       // variables are updated, with the outcome of potential callbacks. | 
|  530       bool listenerHasError = hasError; |  454       bool listenerHasValue = true; | 
|  531       final sourceValue = hasError ? source._error : source._value; |  455       final sourceValue = hasError ? null : source._value; | 
|  532       var listenerValueOrError = sourceValue; |  456       var listenerValueOrError = sourceValue; | 
|  533       // Set to true if a whenComplete needs to wait for a future. |  457       // Set to true if a whenComplete needs to wait for a future. | 
|  534       // The whenComplete action will resume the propagation by itself. |  458       // The whenComplete action will resume the propagation by itself. | 
|  535       bool isPropagationAborted = false; |  459       bool isPropagationAborted = false; | 
|  536       // TODO(floitsch): mark the listener as pending completion. Currently |  460       // TODO(floitsch): mark the listener as pending completion. Currently | 
|  537       // we can't do this, since the markPendingCompletion verifies that |  461       // we can't do this, since the markPendingCompletion verifies that | 
|  538       // the future is not already marked (or chained). |  462       // the future is not already marked (or chained). | 
|  539       // Only if we either have an error or callbacks, go into this, somewhat |  463       // Only if we either have an error or callbacks, go into this, somewhat | 
|  540       // expensive, branch. Here we'll enter/leave the zone. Many futures |  464       // expensive, branch. Here we'll enter/leave the zone. Many futures | 
|  541       // doesn't have callbacks, so this is a significant optimization. |  465       // doesn't have callbacks, so this is a significant optimization. | 
|  542       if (hasError || (listener.handlesValue || listener.handlesComplete)) { |  466       if (hasError || (listener.handlesValue || listener.handlesComplete)) { | 
|  543         Zone zone = listener._zone; |  467         Zone zone = listener._zone; | 
 |  468         if (hasError && !source._zone.inSameErrorZone(zone)) { | 
 |  469           // Don't cross zone boundaries with errors. | 
 |  470           AsyncError asyncError = source._error; | 
 |  471           source._zone.handleUncaughtError( | 
 |  472               asyncError.error, asyncError.stackTrace); | 
 |  473           return; | 
 |  474         } | 
 |  475  | 
 |  476         Zone oldZone; | 
 |  477         if (!identical(Zone.current, zone)) { | 
 |  478           // Change zone if it's not current. | 
 |  479           oldZone = Zone._enter(zone); | 
 |  480         } | 
 |  481  | 
 |  482         bool handleValueCallback() { | 
 |  483           try { | 
 |  484             listenerValueOrError = zone.runUnary(listener._onValue, | 
 |  485                                                  sourceValue); | 
 |  486             return true; | 
 |  487           } catch (e, s) { | 
 |  488             listenerValueOrError = new AsyncError(e, s); | 
 |  489             return false; | 
 |  490           } | 
 |  491         } | 
|  544  |  492  | 
|  545         void handleError() { |  493         void handleError() { | 
|  546           assert(listener.handlesError); |  | 
|  547           AsyncError asyncError = source._error; |  494           AsyncError asyncError = source._error; | 
|  548           bool matchesTest = true; |  495           bool matchesTest = true; | 
|  549           if (listener.hasErrorTest) { |  496           if (listener.hasErrorTest) { | 
|  550             _FutureErrorTest test = listener._errorTest; |  497             _FutureErrorTest test = listener._errorTest; | 
|  551             try { |  498             try { | 
|  552               matchesTest = zone.runUnary(test, asyncError.error); |  499               matchesTest = zone.runUnary(test, asyncError.error); | 
|  553             } catch (e, s) { |  500             } catch (e, s) { | 
|  554               listenerValueOrError = identical(asyncError.error, e) ? |  501               listenerValueOrError = identical(asyncError.error, e) ? | 
|  555                   asyncError : new AsyncError(e, s); |  502                   asyncError : new AsyncError(e, s); | 
|  556               listenerHasError = true; |  503               listenerHasValue = false; | 
|  557               return; |  504               return; | 
|  558             } |  505             } | 
|  559           } |  506           } | 
|  560           if (matchesTest) { |  507           Function errorCallback = listener._onError; | 
|  561             Function errorCallback = listener._onError; |  508           if (matchesTest && errorCallback != null) { | 
|  562             assert(errorCallback != null); |  | 
|  563             try { |  509             try { | 
|  564               if (errorCallback is ZoneBinaryCallback) { |  510               if (errorCallback is ZoneBinaryCallback) { | 
|  565                 listenerValueOrError = zone.runBinary(errorCallback, |  511                 listenerValueOrError = zone.runBinary(errorCallback, | 
|  566                                                       asyncError.error, |  512                                                       asyncError.error, | 
|  567                                                       asyncError.stackTrace); |  513                                                       asyncError.stackTrace); | 
|  568               } else { |  514               } else { | 
|  569                 listenerValueOrError = zone.runUnary(errorCallback, |  515                 listenerValueOrError = zone.runUnary(errorCallback, | 
|  570                                                      asyncError.error); |  516                                                      asyncError.error); | 
|  571               } |  517               } | 
|  572             } catch (e, s) { |  518             } catch (e, s) { | 
|  573               listenerValueOrError = identical(asyncError.error, e) ? |  519               listenerValueOrError = identical(asyncError.error, e) ? | 
|  574                   asyncError : new AsyncError(e, s); |  520                   asyncError : new AsyncError(e, s); | 
|  575               listenerHasError = true; |  521               listenerHasValue = false; | 
|  576               return; |  522               return; | 
|  577             } |  523             } | 
|  578             listenerHasError = false; |  524             listenerHasValue = true; | 
 |  525           } else { | 
 |  526             // Copy over the error from the source. | 
 |  527             listenerValueOrError = asyncError; | 
 |  528             listenerHasValue = false; | 
|  579           } |  529           } | 
|  580         } |  530         } | 
|  581  |  531  | 
|  582         void handleWhenCompleteCallback() { |  532         void handleWhenCompleteCallback() { | 
|  583           var completeResult; |  533           var completeResult; | 
|  584           try { |  534           try { | 
|  585             completeResult = zone.run(listener._whenCompleteAction); |  535             completeResult = zone.run(listener._whenCompleteAction); | 
|  586           } catch (e, s) { |  536           } catch (e, s) { | 
|  587             if (hasError && identical(source._error.error, e)) { |  537             if (hasError && identical(source._error.error, e)) { | 
|  588               listenerValueOrError = source._error; |  538               listenerValueOrError = source._error; | 
|  589             } else { |  539             } else { | 
|  590               listenerValueOrError = new AsyncError(e, s); |  540               listenerValueOrError = new AsyncError(e, s); | 
|  591             } |  541             } | 
|  592             listenerHasError = true; |  542             listenerHasValue = false; | 
|  593             return; |  543             return; | 
|  594           } |  544           } | 
|  595           if (completeResult is Future) { |  545           if (completeResult is Future) { | 
|  596             _Future result = listener.result; |  546             _Future result = listener.result; | 
|  597             result._isChained = true; |  547             result._isChained = true; | 
|  598             isPropagationAborted = true; |  548             isPropagationAborted = true; | 
|  599             final _Future originalSource = source; |  | 
|  600             completeResult.then((ignored) { |  549             completeResult.then((ignored) { | 
|  601               _propagateToFutures(originalSource, |  550               _propagateToListeners(source, new _FutureListener.chain(result)); | 
|  602                                   new _FutureListener.chain(result), |  | 
|  603                                   _UNGUARDED); |  | 
|  604             }, onError: (error, [stackTrace]) { |  551             }, onError: (error, [stackTrace]) { | 
|  605               // When there is an error, we have to make the error the new |  552               // When there is an error, we have to make the error the new | 
|  606               // result of the current listener. |  553               // result of the current listener. | 
|  607               if (completeResult is! _Future) { |  554               if (completeResult is! _Future) { | 
|  608                 // This should be a rare case. |  555                 // This should be a rare case. | 
|  609                 completeResult = new _Future(); |  556                 completeResult = new _Future(); | 
|  610                 completeResult._setError(error, stackTrace); |  557                 completeResult._setError(error, stackTrace); | 
|  611               } |  558               } | 
|  612               _propagateToFutures(completeResult, |  559               _propagateToListeners(completeResult, | 
|  613                                   new _FutureListener.chain(result), |  560                                     new _FutureListener.chain(result)); | 
|  614                                   _UNGUARDED); |  | 
|  615             }); |  561             }); | 
|  616           } |  562           } | 
|  617         } |  563         } | 
|  618  |  564  | 
|  619         Zone oldZone = Zone._enter(zone); |  | 
|  620  |  | 
|  621         if (!hasError) { |  565         if (!hasError) { | 
|  622           if (listener.handlesValue) { |  566           if (listener.handlesValue) { | 
|  623             // Run try/catch in separate function to help compilers. |  567             listenerHasValue = handleValueCallback(); | 
|  624             () { |  | 
|  625               try { |  | 
|  626                 listenerValueOrError = zone.runUnary(listener._onValue, |  | 
|  627                                                      sourceValue); |  | 
|  628                 listenerHasError = false; |  | 
|  629               } catch (e, s) { |  | 
|  630                 listenerValueOrError = new AsyncError(e, s); |  | 
|  631                 listenerHasError = true; |  | 
|  632               } |  | 
|  633             }(); |  | 
|  634             assert(!listener.handlesComplete); |  | 
|  635           } else if (listener.handlesComplete) { |  | 
|  636             // Complete-listeners are distinct from value/error handlers, |  | 
|  637             // so no need to check for a complete handler if it is an error |  | 
|  638             // handler. |  | 
|  639             handleWhenCompleteCallback(); |  | 
|  640           } |  568           } | 
|  641         } else { |  569         } else { | 
|  642           if (!source._zone.inSameErrorZone(zone)) { |  570           handleError(); | 
|  643             // Don't cross zone boundaries with errors. |  | 
|  644             Zone._leave(oldZone); |  | 
|  645             _throwUncaughtError(source, guarded); |  | 
|  646             return; |  | 
|  647           } |  | 
|  648           if (listener.handlesError) { |  | 
|  649             handleError(); |  | 
|  650             assert(!listener.handlesComplete); |  | 
|  651           } else if (listener.handlesComplete) { |  | 
|  652             handleWhenCompleteCallback(); |  | 
|  653           } |  | 
|  654         } |  571         } | 
 |  572         if (listener.handlesComplete) { | 
 |  573           handleWhenCompleteCallback(); | 
 |  574         } | 
 |  575         // If we changed zone, oldZone will not be null. | 
 |  576         if (oldZone != null) Zone._leave(oldZone); | 
|  655  |  577  | 
|  656         Zone._leave(oldZone); |  578         if (isPropagationAborted) return; | 
|  657  |  | 
|  658         if (isPropagationAborted) { |  | 
|  659           // Don't use the value in listenerValueOrError - the whenComplete |  | 
|  660           // handler is handling that result. |  | 
|  661           if (_pendingFutureListeners == null) return; |  | 
|  662           source = null; |  | 
|  663           continue; |  | 
|  664         } |  | 
|  665         // If the listener's value is a future we need to chain it. Note that |  579         // If the listener's value is a future we need to chain it. Note that | 
|  666         // this can only happen if there is a callback. Since 'is' checks |  580         // this can only happen if there is a callback. Since 'is' checks | 
|  667         // can be expensive, we're trying to avoid it. |  581         // can be expensive, we're trying to avoid it. | 
|  668         if (!listenerHasError && |  582         if (listenerHasValue && | 
|  669             !identical(sourceValue, listenerValueOrError) && |  583             !identical(sourceValue, listenerValueOrError) && | 
|  670             listenerValueOrError is Future) { |  584             listenerValueOrError is Future) { | 
|  671           Future chainSource = listenerValueOrError; |  585           Future chainSource = listenerValueOrError; | 
|  672           // Shortcut if the chain-source is already completed. Just continue |  586           // Shortcut if the chain-source is already completed. Just continue | 
|  673           // the loop. |  587           // the loop. | 
|  674           _Future result = listener.result; |  588           _Future result = listener.result; | 
|  675           if (chainSource is _Future) { |  589           if (chainSource is _Future) { | 
|  676             if (chainSource._isComplete) { |  590             if (chainSource._isComplete) { | 
|  677               // Propagate the value (simulating a tail call). |  591               // propagate the value (simulating a tail call). | 
|  678               result._isChained = true; |  592               result._isChained = true; | 
|  679               source = chainSource; |  593               source = chainSource; | 
|  680               listeners = new _FutureListener.chain(result); |  594               listeners = new _FutureListener.chain(result); | 
|  681               continue; |  595               continue; | 
|  682             } else { |  596             } else { | 
|  683               _chainCoreFuture(chainSource, result); |  597               _chainCoreFuture(chainSource, result); | 
|  684             } |  598             } | 
|  685           } else { |  599           } else { | 
|  686             _chainForeignFuture(chainSource, result); |  600             _chainForeignFuture(chainSource, result); | 
|  687           } |  601           } | 
|  688           if (_pendingFutureListeners == null) return; |  602           return; | 
|  689           source = null; |  | 
|  690           continue; |  | 
|  691         } |  603         } | 
|  692       } |  604       } | 
|  693       // Complete the future waiting for the result. |  | 
|  694       _Future result = listener.result; |  605       _Future result = listener.result; | 
|  695       _FutureListener resultListeners = result._removeListeners(); |  606       listeners = result._removeListeners(); | 
|  696       if (!listenerHasError) { |  607       if (listenerHasValue) { | 
|  697         result._setValue(listenerValueOrError); |  608         result._setValue(listenerValueOrError); | 
|  698       } else { |  609       } else { | 
|  699         AsyncError asyncError = listenerValueOrError; |  610         AsyncError asyncError = listenerValueOrError; | 
|  700         result._setErrorObject(asyncError); |  611         result._setErrorObject(asyncError); | 
|  701       } |  612       } | 
|  702       // Prepare for next round. |  613       // Prepare for next round. | 
|  703       source = result; |  614       source = result; | 
|  704       listeners = resultListeners; |  | 
|  705     } |  615     } | 
|  706   } |  616   } | 
|  707  |  617  | 
|  708   Future timeout(Duration timeLimit, {onTimeout()}) { |  618   Future timeout(Duration timeLimit, {onTimeout()}) { | 
|  709     if (_isComplete) return new _Future.immediate(this); |  619     if (_isComplete) return new _Future.immediate(this); | 
|  710     _Future result = new _Future(); |  620     _Future result = new _Future(); | 
|  711     Timer timer; |  621     Timer timer; | 
|  712     if (onTimeout == null) { |  622     if (onTimeout == null) { | 
|  713       timer = new Timer(timeLimit, () { |  623       timer = new Timer(timeLimit, () { | 
|  714         result._completeError(new TimeoutException("Future not completed", |  624         result._completeError(new TimeoutException("Future not completed", | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
|  732       } |  642       } | 
|  733     }, onError: (e, s) { |  643     }, onError: (e, s) { | 
|  734       if (timer.isActive) { |  644       if (timer.isActive) { | 
|  735         timer.cancel(); |  645         timer.cancel(); | 
|  736         result._completeError(e, s); |  646         result._completeError(e, s); | 
|  737       } |  647       } | 
|  738     }); |  648     }); | 
|  739     return result; |  649     return result; | 
|  740   } |  650   } | 
|  741 } |  651 } | 
|  742  |  | 
|  743 class _PendingFutureListeners { |  | 
|  744   final _Future source; |  | 
|  745   final _PendingFutureListeners next; |  | 
|  746   _FutureListener listeners; |  | 
|  747   _PendingFutureListeners(this.source, this.listeners, this.next); |  | 
|  748 } |  | 
| OLD | NEW |