| 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 FutureOr<T> _FutureOnValue<S, T>(S value); | 8 typedef FutureOr<T> _FutureOnValue<S, T>(S 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); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 } | 28 } |
| 29 | 29 |
| 30 void _completeError(Object error, StackTrace stackTrace); | 30 void _completeError(Object error, StackTrace stackTrace); |
| 31 | 31 |
| 32 // The future's _isComplete doesn't take into account pending completions. | 32 // The future's _isComplete doesn't take into account pending completions. |
| 33 // We therefore use _mayComplete. | 33 // We therefore use _mayComplete. |
| 34 bool get isCompleted => !future._mayComplete; | 34 bool get isCompleted => !future._mayComplete; |
| 35 } | 35 } |
| 36 | 36 |
| 37 class _AsyncCompleter<T> extends _Completer<T> { | 37 class _AsyncCompleter<T> extends _Completer<T> { |
| 38 | |
| 39 void complete([FutureOr<T> value]) { | 38 void complete([FutureOr<T> value]) { |
| 40 if (!future._mayComplete) throw new StateError("Future already completed"); | 39 if (!future._mayComplete) throw new StateError("Future already completed"); |
| 41 future._asyncComplete(value); | 40 future._asyncComplete(value); |
| 42 } | 41 } |
| 43 | 42 |
| 44 void _completeError(Object error, StackTrace stackTrace) { | 43 void _completeError(Object error, StackTrace stackTrace) { |
| 45 future._asyncCompleteError(error, stackTrace); | 44 future._asyncCompleteError(error, stackTrace); |
| 46 } | 45 } |
| 47 } | 46 } |
| 48 | 47 |
| 49 class _SyncCompleter<T> extends _Completer<T> { | 48 class _SyncCompleter<T> extends _Completer<T> { |
| 50 void complete([FutureOr<T> value]) { | 49 void complete([FutureOr<T> value]) { |
| 51 if (!future._mayComplete) throw new StateError("Future already completed"); | 50 if (!future._mayComplete) throw new StateError("Future already completed"); |
| 52 future._complete(value); | 51 future._complete(value); |
| 53 } | 52 } |
| 54 | 53 |
| 55 void _completeError(Object error, StackTrace stackTrace) { | 54 void _completeError(Object error, StackTrace stackTrace) { |
| 56 future._completeError(error, stackTrace); | 55 future._completeError(error, stackTrace); |
| 57 } | 56 } |
| 58 } | 57 } |
| 59 | 58 |
| 60 class _FutureListener<S, T> { | 59 class _FutureListener<S, T> { |
| 61 static const int MASK_VALUE = 1; | 60 static const int MASK_VALUE = 1; |
| 62 static const int MASK_ERROR = 2; | 61 static const int MASK_ERROR = 2; |
| 63 static const int MASK_TEST_ERROR = 4; | 62 static const int MASK_TEST_ERROR = 4; |
| 64 static const int MASK_WHENCOMPLETE = 8; | 63 static const int MASK_WHENCOMPLETE = 8; |
| 65 static const int STATE_CHAIN = 0; | 64 static const int STATE_CHAIN = 0; |
| 66 static const int STATE_THEN = MASK_VALUE; | 65 static const int STATE_THEN = MASK_VALUE; |
| 67 // TODO(johnmccutchan): Remove the hard coded value. See #26030. | 66 // TODO(johnmccutchan): Remove the hard coded value. See #26030. |
| 68 static const int STATE_THEN_ONERROR = 3; // MASK_VALUE | MASK_ERROR. | 67 static const int STATE_THEN_ONERROR = 3; // MASK_VALUE | MASK_ERROR. |
| 69 static const int STATE_CATCHERROR = MASK_ERROR; | 68 static const int STATE_CATCHERROR = MASK_ERROR; |
| 70 // TODO(johnmccutchan): Remove the hard coded value. See #26030. | 69 // TODO(johnmccutchan): Remove the hard coded value. See #26030. |
| 71 static const int STATE_CATCHERROR_TEST = 6; // MASK_ERROR | MASK_TEST_ERROR. | 70 static const int STATE_CATCHERROR_TEST = 6; // MASK_ERROR | MASK_TEST_ERROR. |
| 72 static const int STATE_WHENCOMPLETE = MASK_WHENCOMPLETE; | 71 static const int STATE_WHENCOMPLETE = MASK_WHENCOMPLETE; |
| 73 // Listeners on the same future are linked through this link. | 72 // Listeners on the same future are linked through this link. |
| 74 _FutureListener _nextListener = null; | 73 _FutureListener _nextListener = null; |
| 75 // The future to complete when this listener is activated. | 74 // The future to complete when this listener is activated. |
| 76 final _Future<T> result; | 75 final _Future<T> result; |
| 77 // Which fields means what. | 76 // Which fields means what. |
| 78 final int state; | 77 final int state; |
| 79 // Used for then/whenDone callback and error test | 78 // Used for then/whenDone callback and error test |
| 80 final Function callback; | 79 final Function callback; |
| 81 // Used for error callbacks. | 80 // Used for error callbacks. |
| 82 final Function errorCallback; | 81 final Function errorCallback; |
| 83 | 82 |
| 84 _FutureListener.then(this.result, | 83 _FutureListener.then( |
| 85 _FutureOnValue<S, T> onValue, Function errorCallback) | 84 this.result, _FutureOnValue<S, T> onValue, Function errorCallback) |
| 86 : callback = onValue, | 85 : callback = onValue, |
| 87 errorCallback = errorCallback, | 86 errorCallback = errorCallback, |
| 88 state = (errorCallback == null) ? STATE_THEN : STATE_THEN_ONERROR; | 87 state = (errorCallback == null) ? STATE_THEN : STATE_THEN_ONERROR; |
| 89 | 88 |
| 90 _FutureListener.catchError(this.result, | 89 _FutureListener.catchError( |
| 91 this.errorCallback, _FutureErrorTest test) | 90 this.result, this.errorCallback, _FutureErrorTest test) |
| 92 : callback = test, | 91 : callback = test, |
| 93 state = (test == null) ? STATE_CATCHERROR : STATE_CATCHERROR_TEST; | 92 state = (test == null) ? STATE_CATCHERROR : STATE_CATCHERROR_TEST; |
| 94 | 93 |
| 95 _FutureListener.whenComplete(this.result, _FutureAction onComplete) | 94 _FutureListener.whenComplete(this.result, _FutureAction onComplete) |
| 96 : callback = onComplete, | 95 : callback = onComplete, |
| 97 errorCallback = null, | 96 errorCallback = null, |
| 98 state = STATE_WHENCOMPLETE; | 97 state = STATE_WHENCOMPLETE; |
| 99 | 98 |
| 100 Zone get _zone => result._zone; | 99 Zone get _zone => result._zone; |
| 101 | 100 |
| 102 bool get handlesValue => (state & MASK_VALUE != 0); | 101 bool get handlesValue => (state & MASK_VALUE != 0); |
| 103 bool get handlesError => (state & MASK_ERROR != 0); | 102 bool get handlesError => (state & MASK_ERROR != 0); |
| 104 bool get hasErrorTest => (state == STATE_CATCHERROR_TEST); | 103 bool get hasErrorTest => (state == STATE_CATCHERROR_TEST); |
| 105 bool get handlesComplete => (state == STATE_WHENCOMPLETE); | 104 bool get handlesComplete => (state == STATE_WHENCOMPLETE); |
| 106 | 105 |
| 107 | |
| 108 _FutureOnValue<S, T> get _onValue { | 106 _FutureOnValue<S, T> get _onValue { |
| 109 assert(handlesValue); | 107 assert(handlesValue); |
| 110 return callback as Object /*=_FutureOnValue<S, T>*/; | 108 return callback as Object/*=_FutureOnValue<S, T>*/; |
| 111 } | 109 } |
| 110 |
| 112 Function get _onError => errorCallback; | 111 Function get _onError => errorCallback; |
| 113 _FutureErrorTest get _errorTest { | 112 _FutureErrorTest get _errorTest { |
| 114 assert(hasErrorTest); | 113 assert(hasErrorTest); |
| 115 return callback as Object /*=_FutureErrorTest*/; | 114 return callback as Object/*=_FutureErrorTest*/; |
| 116 } | 115 } |
| 116 |
| 117 _FutureAction get _whenCompleteAction { | 117 _FutureAction get _whenCompleteAction { |
| 118 assert(handlesComplete); | 118 assert(handlesComplete); |
| 119 return callback as Object /*=_FutureAction*/; | 119 return callback as Object/*=_FutureAction*/; |
| 120 } | 120 } |
| 121 | 121 |
| 122 /// Whether this listener has an error callback. | 122 /// Whether this listener has an error callback. |
| 123 /// | 123 /// |
| 124 /// This function must only be called if the listener [handlesError]. | 124 /// This function must only be called if the listener [handlesError]. |
| 125 bool get hasErrorCallback { | 125 bool get hasErrorCallback { |
| 126 assert(handlesError); | 126 assert(handlesError); |
| 127 return _onError != null; | 127 return _onError != null; |
| 128 } | 128 } |
| 129 | 129 |
| 130 FutureOr<T> handleValue(S sourceResult) { | 130 FutureOr<T> handleValue(S sourceResult) { |
| 131 return _zone.runUnary<FutureOr<T>, S>( | 131 return _zone.runUnary<FutureOr<T>, S>(_onValue, sourceResult); |
| 132 _onValue, sourceResult); | |
| 133 } | 132 } |
| 134 | 133 |
| 135 bool matchesErrorTest(AsyncError asyncError) { | 134 bool matchesErrorTest(AsyncError asyncError) { |
| 136 if (!hasErrorTest) return true; | 135 if (!hasErrorTest) return true; |
| 137 _FutureErrorTest test = _errorTest; | 136 _FutureErrorTest test = _errorTest; |
| 138 return _zone.runUnary<bool, dynamic>(_errorTest, asyncError.error); | 137 return _zone.runUnary<bool, dynamic>(_errorTest, asyncError.error); |
| 139 } | 138 } |
| 140 | 139 |
| 141 FutureOr<T> handleError(AsyncError asyncError) { | 140 FutureOr<T> handleError(AsyncError asyncError) { |
| 142 assert(handlesError && hasErrorCallback); | 141 assert(handlesError && hasErrorCallback); |
| 143 if (errorCallback is ZoneBinaryCallback) { | 142 if (errorCallback is ZoneBinaryCallback) { |
| 144 var typedErrorCallback = errorCallback as Object | 143 var typedErrorCallback = errorCallback as Object |
| 145 /*=ZoneBinaryCallback<FutureOr<T>, Object, StackTrace>*/; | 144 /*=ZoneBinaryCallback<FutureOr<T>, Object, StackTrace>*/; |
| 146 return _zone.runBinary(typedErrorCallback, | 145 return _zone.runBinary( |
| 147 asyncError.error, | 146 typedErrorCallback, asyncError.error, asyncError.stackTrace); |
| 148 asyncError.stackTrace); | |
| 149 } else { | 147 } else { |
| 150 return _zone.runUnary<FutureOr<T>, dynamic>( | 148 return _zone.runUnary<FutureOr<T>, dynamic>( |
| 151 errorCallback, asyncError.error); | 149 errorCallback, asyncError.error); |
| 152 } | 150 } |
| 153 } | 151 } |
| 154 | 152 |
| 155 dynamic handleWhenComplete() { | 153 dynamic handleWhenComplete() { |
| 156 assert(!handlesError); | 154 assert(!handlesError); |
| 157 return _zone.run(_whenCompleteAction); | 155 return _zone.run(_whenCompleteAction); |
| 158 } | 156 } |
| 159 } | 157 } |
| 160 | 158 |
| 161 class _Future<T> implements Future<T> { | 159 class _Future<T> implements Future<T> { |
| 162 /// Initial state, waiting for a result. In this state, the | 160 /// Initial state, waiting for a result. In this state, the |
| 163 /// [resultOrListeners] field holds a single-linked list of | 161 /// [resultOrListeners] field holds a single-linked list of |
| 164 /// [_FutureListener] listeners. | 162 /// [_FutureListener] listeners. |
| 165 static const int _INCOMPLETE = 0; | 163 static const int _INCOMPLETE = 0; |
| 164 |
| 166 /// Pending completion. Set when completed using [_asyncComplete] or | 165 /// Pending completion. Set when completed using [_asyncComplete] or |
| 167 /// [_asyncCompleteError]. It is an error to try to complete it again. | 166 /// [_asyncCompleteError]. It is an error to try to complete it again. |
| 168 /// [resultOrListeners] holds listeners. | 167 /// [resultOrListeners] holds listeners. |
| 169 static const int _PENDING_COMPLETE = 1; | 168 static const int _PENDING_COMPLETE = 1; |
| 169 |
| 170 /// The future has been chained to another future. The result of that | 170 /// The future has been chained to another future. The result of that |
| 171 /// other future becomes the result of this future as well. | 171 /// other future becomes the result of this future as well. |
| 172 /// [resultOrListeners] contains the source future. | 172 /// [resultOrListeners] contains the source future. |
| 173 static const int _CHAINED = 2; | 173 static const int _CHAINED = 2; |
| 174 |
| 174 /// The future has been completed with a value result. | 175 /// The future has been completed with a value result. |
| 175 static const int _VALUE = 4; | 176 static const int _VALUE = 4; |
| 177 |
| 176 /// The future has been completed with an error result. | 178 /// The future has been completed with an error result. |
| 177 static const int _ERROR = 8; | 179 static const int _ERROR = 8; |
| 178 | 180 |
| 179 /** Whether the future is complete, and as what. */ | 181 /** Whether the future is complete, and as what. */ |
| 180 int _state = _INCOMPLETE; | 182 int _state = _INCOMPLETE; |
| 181 | 183 |
| 182 /** | 184 /** |
| 183 * Zone that the future was completed from. | 185 * Zone that the future was completed from. |
| 184 * This is the zone that an error result belongs to. | 186 * This is the zone that an error result belongs to. |
| 185 * | 187 * |
| (...skipping 24 matching lines...) Expand all Loading... |
| 210 | 212 |
| 211 /// Valid types for value: `T` or `Future<T>`. | 213 /// Valid types for value: `T` or `Future<T>`. |
| 212 _Future.immediate(value) { | 214 _Future.immediate(value) { |
| 213 _asyncComplete(value); | 215 _asyncComplete(value); |
| 214 } | 216 } |
| 215 | 217 |
| 216 _Future.immediateError(var error, [StackTrace stackTrace]) { | 218 _Future.immediateError(var error, [StackTrace stackTrace]) { |
| 217 _asyncCompleteError(error, stackTrace); | 219 _asyncCompleteError(error, stackTrace); |
| 218 } | 220 } |
| 219 | 221 |
| 220 bool get _mayComplete => _state == _INCOMPLETE; | 222 bool get _mayComplete => _state == _INCOMPLETE; |
| 221 bool get _isPendingComplete => _state == _PENDING_COMPLETE; | 223 bool get _isPendingComplete => _state == _PENDING_COMPLETE; |
| 222 bool get _mayAddListener => _state <= _PENDING_COMPLETE; | 224 bool get _mayAddListener => _state <= _PENDING_COMPLETE; |
| 223 bool get _isChained => _state == _CHAINED; | 225 bool get _isChained => _state == _CHAINED; |
| 224 bool get _isComplete => _state >= _VALUE; | 226 bool get _isComplete => _state >= _VALUE; |
| 225 bool get _hasError => _state == _ERROR; | 227 bool get _hasError => _state == _ERROR; |
| 226 | 228 |
| 227 void _setChained(_Future source) { | 229 void _setChained(_Future source) { |
| 228 assert(_mayAddListener); | 230 assert(_mayAddListener); |
| 229 _state = _CHAINED; | 231 _state = _CHAINED; |
| 230 _resultOrListeners = source; | 232 _resultOrListeners = source; |
| 231 } | 233 } |
| 232 | 234 |
| 233 Future<E> then<E>( | 235 Future<E> then<E>(FutureOr<E> f(T value), {Function onError}) { |
| 234 FutureOr<E> f(T value), { Function onError }) { | |
| 235 Zone currentZone = Zone.current; | 236 Zone currentZone = Zone.current; |
| 236 ZoneUnaryCallback registered; | 237 ZoneUnaryCallback registered; |
| 237 if (!identical(currentZone, _ROOT_ZONE)) { | 238 if (!identical(currentZone, _ROOT_ZONE)) { |
| 238 f = currentZone.registerUnaryCallback<FutureOr<E>, T>(f); | 239 f = currentZone.registerUnaryCallback<FutureOr<E>, T>(f); |
| 239 if (onError != null) { | 240 if (onError != null) { |
| 240 onError = _registerErrorHandler<E>(onError, currentZone); | 241 onError = _registerErrorHandler<E>(onError, currentZone); |
| 241 } | 242 } |
| 242 } | 243 } |
| 243 return _thenNoZoneRegistration<E>(f, onError); | 244 return _thenNoZoneRegistration<E>(f, onError); |
| 244 } | 245 } |
| 245 | 246 |
| 246 // This method is used by async/await. | 247 // This method is used by async/await. |
| 247 Future<E> _thenNoZoneRegistration<E>(f(T value), Function onError) { | 248 Future<E> _thenNoZoneRegistration<E>(f(T value), Function onError) { |
| 248 _Future<E> result = new _Future<E>(); | 249 _Future<E> result = new _Future<E>(); |
| 249 _addListener(new _FutureListener<T, E>.then(result, f, onError)); | 250 _addListener(new _FutureListener<T, E>.then(result, f, onError)); |
| 250 return result; | 251 return result; |
| 251 } | 252 } |
| 252 | 253 |
| 253 Future<T> catchError(Function onError, { bool test(error) }) { | 254 Future<T> catchError(Function onError, {bool test(error)}) { |
| 254 _Future<T> result = new _Future<T>(); | 255 _Future<T> result = new _Future<T>(); |
| 255 if (!identical(result._zone, _ROOT_ZONE)) { | 256 if (!identical(result._zone, _ROOT_ZONE)) { |
| 256 onError = _registerErrorHandler<T>(onError, result._zone); | 257 onError = _registerErrorHandler<T>(onError, result._zone); |
| 257 if (test != null) test = result._zone.registerUnaryCallback(test); | 258 if (test != null) test = result._zone.registerUnaryCallback(test); |
| 258 } | 259 } |
| 259 _addListener(new _FutureListener<T, T>.catchError( | 260 _addListener(new _FutureListener<T, T>.catchError(result, onError, test)); |
| 260 result, onError, test)); | |
| 261 return result; | 261 return result; |
| 262 } | 262 } |
| 263 | 263 |
| 264 Future<T> whenComplete(action()) { | 264 Future<T> whenComplete(action()) { |
| 265 _Future<T> result = new _Future<T>(); | 265 _Future<T> result = new _Future<T>(); |
| 266 if (!identical(result._zone, _ROOT_ZONE)) { | 266 if (!identical(result._zone, _ROOT_ZONE)) { |
| 267 action = result._zone.registerCallback<dynamic>(action); | 267 action = result._zone.registerCallback<dynamic>(action); |
| 268 } | 268 } |
| 269 _addListener(new _FutureListener<T, T>.whenComplete(result, action)); | 269 _addListener(new _FutureListener<T, T>.whenComplete(result, action)); |
| 270 return result; | 270 return result; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 287 return _resultOrListeners; | 287 return _resultOrListeners; |
| 288 } | 288 } |
| 289 | 289 |
| 290 _Future get _chainSource { | 290 _Future get _chainSource { |
| 291 assert(_isChained); | 291 assert(_isChained); |
| 292 return _resultOrListeners; | 292 return _resultOrListeners; |
| 293 } | 293 } |
| 294 | 294 |
| 295 // This method is used by async/await. | 295 // This method is used by async/await. |
| 296 void _setValue(T value) { | 296 void _setValue(T value) { |
| 297 assert(!_isComplete); // But may have a completion pending. | 297 assert(!_isComplete); // But may have a completion pending. |
| 298 _state = _VALUE; | 298 _state = _VALUE; |
| 299 _resultOrListeners = value; | 299 _resultOrListeners = value; |
| 300 } | 300 } |
| 301 | 301 |
| 302 void _setErrorObject(AsyncError error) { | 302 void _setErrorObject(AsyncError error) { |
| 303 assert(!_isComplete); // But may have a completion pending. | 303 assert(!_isComplete); // But may have a completion pending. |
| 304 _state = _ERROR; | 304 _state = _ERROR; |
| 305 _resultOrListeners = error; | 305 _resultOrListeners = error; |
| 306 } | 306 } |
| 307 | 307 |
| 308 void _setError(Object error, StackTrace stackTrace) { | 308 void _setError(Object error, StackTrace stackTrace) { |
| 309 _setErrorObject(new AsyncError(error, stackTrace)); | 309 _setErrorObject(new AsyncError(error, stackTrace)); |
| 310 } | 310 } |
| 311 | 311 |
| 312 /// Copy the completion result of [source] into this future. | 312 /// Copy the completion result of [source] into this future. |
| 313 /// | 313 /// |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 402 // for _Future than _chainCoreFuture, so you must use _chainCoreFuture | 402 // for _Future than _chainCoreFuture, so you must use _chainCoreFuture |
| 403 // in that case. | 403 // in that case. |
| 404 static void _chainForeignFuture(Future source, _Future target) { | 404 static void _chainForeignFuture(Future source, _Future target) { |
| 405 assert(!target._isComplete); | 405 assert(!target._isComplete); |
| 406 assert(source is! _Future); | 406 assert(source is! _Future); |
| 407 | 407 |
| 408 // Mark the target as chained (and as such half-completed). | 408 // Mark the target as chained (and as such half-completed). |
| 409 target._setPendingComplete(); | 409 target._setPendingComplete(); |
| 410 try { | 410 try { |
| 411 source.then((value) { | 411 source.then((value) { |
| 412 assert(target._isPendingComplete); | 412 assert(target._isPendingComplete); |
| 413 // The "value" may be another future if the foreign future | 413 // The "value" may be another future if the foreign future |
| 414 // implementation is mis-behaving, | 414 // implementation is mis-behaving, |
| 415 // so use _complete instead of _completeWithValue. | 415 // so use _complete instead of _completeWithValue. |
| 416 target._clearPendingComplete(); // Clear this first, it's set again. | 416 target._clearPendingComplete(); // Clear this first, it's set again. |
| 417 target._complete(value); | 417 target._complete(value); |
| 418 }, | 418 }, |
| 419 // TODO(floitsch): eventually we would like to make this non-optional | 419 // TODO(floitsch): eventually we would like to make this non-optional |
| 420 // and dependent on the listeners of the target future. If none of | 420 // and dependent on the listeners of the target future. If none of |
| 421 // the target future's listeners want to have the stack trace we don't | 421 // the target future's listeners want to have the stack trace we don't |
| 422 // need a trace. | 422 // need a trace. |
| 423 onError: (error, [stackTrace]) { | 423 onError: (error, [stackTrace]) { |
| 424 assert(target._isPendingComplete); | 424 assert(target._isPendingComplete); |
| 425 target._completeError(error, stackTrace); | 425 target._completeError(error, stackTrace); |
| 426 }); | 426 }); |
| 427 } catch (e, s) { | 427 } catch (e, s) { |
| 428 // This only happens if the `then` call threw synchronously when given | 428 // This only happens if the `then` call threw synchronously when given |
| 429 // valid arguments. | 429 // valid arguments. |
| 430 // That requires a non-conforming implementation of the Future interface, | 430 // That requires a non-conforming implementation of the Future interface, |
| 431 // which should, hopefully, never happen. | 431 // which should, hopefully, never happen. |
| 432 scheduleMicrotask(() { | 432 scheduleMicrotask(() { |
| 433 target._completeError(e, s); | 433 target._completeError(e, s); |
| 434 }); | 434 }); |
| 435 } | 435 } |
| 436 } | 436 } |
| 437 | 437 |
| 438 // Take the value (when completed) of source and complete target with that | 438 // Take the value (when completed) of source and complete target with that |
| 439 // value (or error). This function expects that source is a _Future. | 439 // value (or error). This function expects that source is a _Future. |
| 440 static void _chainCoreFuture(_Future source, _Future target) { | 440 static void _chainCoreFuture(_Future source, _Future target) { |
| 441 assert(target._mayAddListener); // Not completed, not already chained. | 441 assert(target._mayAddListener); // Not completed, not already chained. |
| 442 while (source._isChained) { | 442 while (source._isChained) { |
| 443 source = source._chainSource; | 443 source = source._chainSource; |
| 444 } | 444 } |
| 445 if (source._isComplete) { | 445 if (source._isComplete) { |
| 446 _FutureListener listeners = target._removeListeners(); | 446 _FutureListener listeners = target._removeListeners(); |
| 447 target._cloneResult(source); | 447 target._cloneResult(source); |
| 448 _propagateToListeners(target, listeners); | 448 _propagateToListeners(target, listeners); |
| 449 } else { | 449 } else { |
| 450 _FutureListener listeners = target._resultOrListeners; | 450 _FutureListener listeners = target._resultOrListeners; |
| 451 target._setChained(source); | 451 target._setChained(source); |
| 452 source._prependListeners(listeners); | 452 source._prependListeners(listeners); |
| 453 } | 453 } |
| 454 } | 454 } |
| 455 | 455 |
| 456 void _complete(value) { | 456 void _complete(value) { |
| 457 assert(!_isComplete); | 457 assert(!_isComplete); |
| 458 if (value is Future) { | 458 if (value is Future) { |
| 459 if (value is _Future) { | 459 if (value is _Future) { |
| 460 _chainCoreFuture(value, this); | 460 _chainCoreFuture(value, this); |
| 461 } else { | 461 } else { |
| 462 _chainForeignFuture(value, this); | 462 _chainForeignFuture(value, this); |
| 463 } | 463 } |
| 464 } else { | 464 } else { |
| 465 _FutureListener listeners = _removeListeners(); | 465 _FutureListener listeners = _removeListeners(); |
| 466 _setValue(value as Object /*=T*/); | 466 _setValue(value as Object/*=T*/); |
| 467 _propagateToListeners(this, listeners); | 467 _propagateToListeners(this, listeners); |
| 468 } | 468 } |
| 469 } | 469 } |
| 470 | 470 |
| 471 void _completeWithValue(T value) { | 471 void _completeWithValue(T value) { |
| 472 assert(!_isComplete); | 472 assert(!_isComplete); |
| 473 assert(value is! Future); | 473 assert(value is! Future); |
| 474 | 474 |
| 475 _FutureListener listeners = _removeListeners(); | 475 _FutureListener listeners = _removeListeners(); |
| 476 _setValue(value); | 476 _setValue(value); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 493 // The first case means that we must not immediately complete the Future, | 493 // The first case means that we must not immediately complete the Future, |
| 494 // as our code would immediately start propagating the error without | 494 // as our code would immediately start propagating the error without |
| 495 // giving the time to install error-handlers. | 495 // giving the time to install error-handlers. |
| 496 // However the second case requires us to deal with the value immediately. | 496 // However the second case requires us to deal with the value immediately. |
| 497 // Otherwise the value could complete with an error and report an | 497 // Otherwise the value could complete with an error and report an |
| 498 // unhandled error, even though we know we are already going to listen to | 498 // unhandled error, even though we know we are already going to listen to |
| 499 // it. | 499 // it. |
| 500 | 500 |
| 501 if (value is Future) { | 501 if (value is Future) { |
| 502 // Assign to typed variables so we get earlier checks in checked mode. | 502 // Assign to typed variables so we get earlier checks in checked mode. |
| 503 Future<T> typedFuture = value as Object /*=Future<T>*/; | 503 Future<T> typedFuture = value as Object/*=Future<T>*/; |
| 504 if (typedFuture is _Future) { | 504 if (typedFuture is _Future) { |
| 505 _Future<T> coreFuture = typedFuture; | 505 _Future<T> coreFuture = typedFuture; |
| 506 if (coreFuture._hasError) { | 506 if (coreFuture._hasError) { |
| 507 // Case 1 from above. Delay completion to enable the user to register | 507 // Case 1 from above. Delay completion to enable the user to register |
| 508 // callbacks. | 508 // callbacks. |
| 509 _setPendingComplete(); | 509 _setPendingComplete(); |
| 510 _zone.scheduleMicrotask(() { | 510 _zone.scheduleMicrotask(() { |
| 511 _chainCoreFuture(coreFuture, this); | 511 _chainCoreFuture(coreFuture, this); |
| 512 }); | 512 }); |
| 513 } else { | 513 } else { |
| 514 _chainCoreFuture(coreFuture, this); | 514 _chainCoreFuture(coreFuture, this); |
| 515 } | 515 } |
| 516 } else { | 516 } else { |
| 517 // Case 2 from above. Chain the future immediately. | 517 // Case 2 from above. Chain the future immediately. |
| 518 // Note that we are still completing asynchronously (through | 518 // Note that we are still completing asynchronously (through |
| 519 // _chainForeignFuture). | 519 // _chainForeignFuture). |
| 520 _chainForeignFuture(typedFuture, this); | 520 _chainForeignFuture(typedFuture, this); |
| 521 } | 521 } |
| 522 return; | 522 return; |
| 523 } | 523 } |
| 524 T typedValue = value as Object /*=T*/; | 524 T typedValue = value as Object/*=T*/; |
| 525 | 525 |
| 526 _setPendingComplete(); | 526 _setPendingComplete(); |
| 527 _zone.scheduleMicrotask(() { | 527 _zone.scheduleMicrotask(() { |
| 528 _completeWithValue(typedValue); | 528 _completeWithValue(typedValue); |
| 529 }); | 529 }); |
| 530 } | 530 } |
| 531 | 531 |
| 532 void _asyncCompleteError(error, StackTrace stackTrace) { | 532 void _asyncCompleteError(error, StackTrace stackTrace) { |
| 533 assert(!_isComplete); | 533 assert(!_isComplete); |
| 534 | 534 |
| 535 _setPendingComplete(); | 535 _setPendingComplete(); |
| 536 _zone.scheduleMicrotask(() { | 536 _zone.scheduleMicrotask(() { |
| 537 _completeError(error, stackTrace); | 537 _completeError(error, stackTrace); |
| 538 }); | 538 }); |
| 539 } | 539 } |
| 540 | 540 |
| 541 /** | 541 /** |
| 542 * Propagates the value/error of [source] to its [listeners], executing the | 542 * Propagates the value/error of [source] to its [listeners], executing the |
| 543 * listeners' callbacks. | 543 * listeners' callbacks. |
| 544 */ | 544 */ |
| 545 static void _propagateToListeners(_Future source, _FutureListener listeners) { | 545 static void _propagateToListeners(_Future source, _FutureListener listeners) { |
| 546 while (true) { | 546 while (true) { |
| 547 assert(source._isComplete); | 547 assert(source._isComplete); |
| 548 bool hasError = source._hasError; | 548 bool hasError = source._hasError; |
| 549 if (listeners == null) { | 549 if (listeners == null) { |
| 550 if (hasError) { | 550 if (hasError) { |
| 551 AsyncError asyncError = source._error; | 551 AsyncError asyncError = source._error; |
| 552 source._zone.handleUncaughtError( | 552 source._zone |
| 553 asyncError.error, asyncError.stackTrace); | 553 .handleUncaughtError(asyncError.error, asyncError.stackTrace); |
| 554 } | 554 } |
| 555 return; | 555 return; |
| 556 } | 556 } |
| 557 // Usually futures only have one listener. If they have several, we | 557 // Usually futures only have one listener. If they have several, we |
| 558 // call handle them separately in recursive calls, continuing | 558 // call handle them separately in recursive calls, continuing |
| 559 // here only when there is only one listener left. | 559 // here only when there is only one listener left. |
| 560 while (listeners._nextListener != null) { | 560 while (listeners._nextListener != null) { |
| 561 _FutureListener listener = listeners; | 561 _FutureListener listener = listeners; |
| 562 listeners = listener._nextListener; | 562 listeners = listener._nextListener; |
| 563 listener._nextListener = null; | 563 listener._nextListener = null; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 576 var listenerValueOrError = sourceResult; | 576 var listenerValueOrError = sourceResult; |
| 577 | 577 |
| 578 // Only if we either have an error or callbacks, go into this, somewhat | 578 // Only if we either have an error or callbacks, go into this, somewhat |
| 579 // expensive, branch. Here we'll enter/leave the zone. Many futures | 579 // expensive, branch. Here we'll enter/leave the zone. Many futures |
| 580 // don't have callbacks, so this is a significant optimization. | 580 // don't have callbacks, so this is a significant optimization. |
| 581 if (hasError || listener.handlesValue || listener.handlesComplete) { | 581 if (hasError || listener.handlesValue || listener.handlesComplete) { |
| 582 Zone zone = listener._zone; | 582 Zone zone = listener._zone; |
| 583 if (hasError && !source._zone.inSameErrorZone(zone)) { | 583 if (hasError && !source._zone.inSameErrorZone(zone)) { |
| 584 // Don't cross zone boundaries with errors. | 584 // Don't cross zone boundaries with errors. |
| 585 AsyncError asyncError = source._error; | 585 AsyncError asyncError = source._error; |
| 586 source._zone.handleUncaughtError( | 586 source._zone |
| 587 asyncError.error, asyncError.stackTrace); | 587 .handleUncaughtError(asyncError.error, asyncError.stackTrace); |
| 588 return; | 588 return; |
| 589 } | 589 } |
| 590 | 590 |
| 591 Zone oldZone; | 591 Zone oldZone; |
| 592 if (!identical(Zone.current, zone)) { | 592 if (!identical(Zone.current, zone)) { |
| 593 // Change zone if it's not current. | 593 // Change zone if it's not current. |
| 594 oldZone = Zone._enter(zone); | 594 oldZone = Zone._enter(zone); |
| 595 } | 595 } |
| 596 | 596 |
| 597 // These callbacks are abstracted to isolate the try/catch blocks | 597 // These callbacks are abstracted to isolate the try/catch blocks |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 652 } catch (e, s) { | 652 } catch (e, s) { |
| 653 if (identical(source._error.error, e)) { | 653 if (identical(source._error.error, e)) { |
| 654 listenerValueOrError = source._error; | 654 listenerValueOrError = source._error; |
| 655 } else { | 655 } else { |
| 656 listenerValueOrError = new AsyncError(e, s); | 656 listenerValueOrError = new AsyncError(e, s); |
| 657 } | 657 } |
| 658 listenerHasError = true; | 658 listenerHasError = true; |
| 659 } | 659 } |
| 660 } | 660 } |
| 661 | 661 |
| 662 | |
| 663 if (listener.handlesComplete) { | 662 if (listener.handlesComplete) { |
| 664 handleWhenCompleteCallback(); | 663 handleWhenCompleteCallback(); |
| 665 } else if (!hasError) { | 664 } else if (!hasError) { |
| 666 if (listener.handlesValue) { | 665 if (listener.handlesValue) { |
| 667 handleValueCallback(); | 666 handleValueCallback(); |
| 668 } | 667 } |
| 669 } else { | 668 } else { |
| 670 if (listener.handlesError) { | 669 if (listener.handlesError) { |
| 671 handleError(); | 670 handleError(); |
| 672 } | 671 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 709 source = result; | 708 source = result; |
| 710 } | 709 } |
| 711 } | 710 } |
| 712 | 711 |
| 713 Future<T> timeout(Duration timeLimit, {onTimeout()}) { | 712 Future<T> timeout(Duration timeLimit, {onTimeout()}) { |
| 714 if (_isComplete) return new _Future.immediate(this); | 713 if (_isComplete) return new _Future.immediate(this); |
| 715 _Future<T> result = new _Future<T>(); | 714 _Future<T> result = new _Future<T>(); |
| 716 Timer timer; | 715 Timer timer; |
| 717 if (onTimeout == null) { | 716 if (onTimeout == null) { |
| 718 timer = new Timer(timeLimit, () { | 717 timer = new Timer(timeLimit, () { |
| 719 result._completeError(new TimeoutException("Future not completed", | 718 result._completeError( |
| 720 timeLimit)); | 719 new TimeoutException("Future not completed", timeLimit)); |
| 721 }); | 720 }); |
| 722 } else { | 721 } else { |
| 723 Zone zone = Zone.current; | 722 Zone zone = Zone.current; |
| 724 onTimeout = zone.registerCallback(onTimeout); | 723 onTimeout = zone.registerCallback(onTimeout); |
| 725 timer = new Timer(timeLimit, () { | 724 timer = new Timer(timeLimit, () { |
| 726 try { | 725 try { |
| 727 result._complete(zone.run(onTimeout)); | 726 result._complete(zone.run(onTimeout)); |
| 728 } catch (e, s) { | 727 } catch (e, s) { |
| 729 result._completeError(e, s); | 728 result._completeError(e, s); |
| 730 } | 729 } |
| 731 }); | 730 }); |
| 732 } | 731 } |
| 733 this.then((T v) { | 732 this.then((T v) { |
| 734 if (timer.isActive) { | 733 if (timer.isActive) { |
| 735 timer.cancel(); | 734 timer.cancel(); |
| 736 result._completeWithValue(v); | 735 result._completeWithValue(v); |
| 737 } | 736 } |
| 738 }, onError: (e, s) { | 737 }, onError: (e, s) { |
| 739 if (timer.isActive) { | 738 if (timer.isActive) { |
| 740 timer.cancel(); | 739 timer.cancel(); |
| 741 result._completeError(e, s); | 740 result._completeError(e, s); |
| 742 } | 741 } |
| 743 }); | 742 }); |
| 744 return result; | 743 return result; |
| 745 } | 744 } |
| 746 } | 745 } |
| OLD | NEW |