Chromium Code Reviews| 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 typedef dynamic _FutureOnError(error); | 9 typedef dynamic _FutureOnError(error); |
| 10 /** Test used by [Future.catchError] to handle skip some errors. */ | 10 /** Test used by [Future.catchError] to handle skip some errors. */ |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 69 // just use the PENDING_COMPLETE state instead. | 69 // just use the PENDING_COMPLETE state instead. |
| 70 static const int _CHAINED = 2; | 70 static const int _CHAINED = 2; |
| 71 /// The future has been completed with a value result. | 71 /// The future has been completed with a value result. |
| 72 static const int _VALUE = 4; | 72 static const int _VALUE = 4; |
| 73 /// The future has been completed with an error result. | 73 /// The future has been completed with an error result. |
| 74 static const int _ERROR = 8; | 74 static const int _ERROR = 8; |
| 75 | 75 |
| 76 /** Whether the future is complete, and as what. */ | 76 /** Whether the future is complete, and as what. */ |
| 77 int _state = _INCOMPLETE; | 77 int _state = _INCOMPLETE; |
| 78 | 78 |
| 79 final _Zone _zone = _Zone.current.fork(); | 79 final Zone _zone = Zone.current; |
| 80 | 80 |
| 81 bool get _mayComplete => _state == _INCOMPLETE; | 81 bool get _mayComplete => _state == _INCOMPLETE; |
| 82 bool get _isChained => _state == _CHAINED; | 82 bool get _isChained => _state == _CHAINED; |
| 83 bool get _isComplete => _state >= _VALUE; | 83 bool get _isComplete => _state >= _VALUE; |
| 84 bool get _hasValue => _state == _VALUE; | 84 bool get _hasValue => _state == _VALUE; |
| 85 bool get _hasError => _state == _ERROR; | 85 bool get _hasError => _state == _ERROR; |
| 86 | 86 |
| 87 set _isChained(bool value) { | 87 set _isChained(bool value) { |
| 88 if (value) { | 88 if (value) { |
| 89 assert(!_isComplete); | 89 assert(!_isComplete); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 149 _onErrorCallback = null, _whenCompleteActionCallback = null { | 149 _onErrorCallback = null, _whenCompleteActionCallback = null { |
| 150 _asyncComplete(value); | 150 _asyncComplete(value); |
| 151 } | 151 } |
| 152 | 152 |
| 153 _Future.immediateError(var error, [Object stackTrace]) | 153 _Future.immediateError(var error, [Object stackTrace]) |
| 154 : _onValueCallback = null, _errorTestCallback = null, | 154 : _onValueCallback = null, _errorTestCallback = null, |
| 155 _onErrorCallback = null, _whenCompleteActionCallback = null { | 155 _onErrorCallback = null, _whenCompleteActionCallback = null { |
| 156 _asyncCompleteError(error, stackTrace); | 156 _asyncCompleteError(error, stackTrace); |
| 157 } | 157 } |
| 158 | 158 |
| 159 _Future._then(this._onValueCallback, this._onErrorCallback) | 159 _Future._then(onValueCallback(value), onErrorCallback(e)) |
| 160 : _errorTestCallback = null, _whenCompleteActionCallback = null { | 160 : _onValueCallback = Zone._current.registerCallback1(onValueCallback), |
|
Lasse Reichstein Nielsen
2013/09/23 14:24:12
This uses Zone._current here because that is the z
floitsch
2013/09/23 17:12:07
done.
And made it Zone.current instead of Zone._cu
| |
| 161 _zone.expectCallback(); | 161 _onErrorCallback = Zone._current.registerCallback1(onErrorCallback), |
| 162 } | 162 _errorTestCallback = null, |
| 163 _whenCompleteActionCallback = null; | |
| 163 | 164 |
| 164 _Future._catchError(this._onErrorCallback, this._errorTestCallback) | 165 _Future._catchError(onErrorCallback(e), bool errorTestCallback(e)) |
| 165 : _onValueCallback = null, _whenCompleteActionCallback = null { | 166 : _onErrorCallback = Zone._current.registerCallback1(onErrorCallback), |
| 166 _zone.expectCallback(); | 167 _errorTestCallback = Zone._current.registerCallback1(errorTestCallback), |
| 167 } | 168 _onValueCallback = null, |
| 169 _whenCompleteActionCallback = null; | |
| 168 | 170 |
| 169 _Future._whenComplete(this._whenCompleteActionCallback) | 171 _Future._whenComplete(whenCompleteActionCallback()) |
| 170 : _onValueCallback = null, _errorTestCallback = null, | 172 : _whenCompleteActionCallback = |
| 171 _onErrorCallback = null { | 173 Zone._current.registerCallback(whenCompleteActionCallback), |
| 172 _zone.expectCallback(); | 174 _onValueCallback = null, |
| 173 } | 175 _errorTestCallback = null, |
| 176 _onErrorCallback = null; | |
| 174 | 177 |
| 175 Future then(f(T value), { onError(error) }) { | 178 Future then(f(T value), { onError(error) }) { |
| 176 _Future result; | 179 _Future result; |
| 177 result = new _Future._then(f, onError); | 180 result = new _Future._then(f, onError); |
| 178 _addListener(result); | 181 _addListener(result); |
| 179 return result; | 182 return result; |
| 180 } | 183 } |
| 181 | 184 |
| 182 Future catchError(f(error), { bool test(error) }) { | 185 Future catchError(f(error), { bool test(error) }) { |
| 183 _Future result = new _Future._catchError(f, test); | 186 _Future result = new _Future._catchError(f, test); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 217 void _setError(Object error) { | 220 void _setError(Object error) { |
| 218 assert(!_isComplete); // But may have a completion pending. | 221 assert(!_isComplete); // But may have a completion pending. |
| 219 _state = _ERROR; | 222 _state = _ERROR; |
| 220 _resultOrListeners = error; | 223 _resultOrListeners = error; |
| 221 } | 224 } |
| 222 | 225 |
| 223 void _addListener(_Future listener) { | 226 void _addListener(_Future listener) { |
| 224 assert(listener._nextListener == null); | 227 assert(listener._nextListener == null); |
| 225 if (_isComplete) { | 228 if (_isComplete) { |
| 226 // Handle late listeners asynchronously. | 229 // Handle late listeners asynchronously. |
| 227 runAsync(() { | 230 _zone.scheduleMicrotask(() { |
| 228 _propagateToListeners(this, listener); | 231 _propagateToListeners(this, listener); |
| 229 }); | 232 }); |
| 230 } else { | 233 } else { |
| 231 listener._nextListener = _resultOrListeners; | 234 listener._nextListener = _resultOrListeners; |
| 232 _resultOrListeners = listener; | 235 _resultOrListeners = listener; |
| 233 } | 236 } |
| 234 } | 237 } |
| 235 | 238 |
| 236 _Future _removeListeners() { | 239 _Future _removeListeners() { |
| 237 // Reverse listeners before returning them, so the resulting list is in | 240 // Reverse listeners before returning them, so the resulting list is in |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 334 (value is! _Future || !(value as _Future)._isComplete)) { | 337 (value is! _Future || !(value as _Future)._isComplete)) { |
| 335 // Case 2 from above. We need to register. | 338 // Case 2 from above. We need to register. |
| 336 // Note that we are still completing asynchronously: either we register | 339 // Note that we are still completing asynchronously: either we register |
| 337 // through .then (in which case the completing is asynchronous), or we | 340 // through .then (in which case the completing is asynchronous), or we |
| 338 // have a _Future which isn't complete yet. | 341 // have a _Future which isn't complete yet. |
| 339 _complete(value); | 342 _complete(value); |
| 340 return; | 343 return; |
| 341 } | 344 } |
| 342 | 345 |
| 343 _markPendingCompletion(); | 346 _markPendingCompletion(); |
| 344 runAsync(() { | 347 _zone.scheduleMicrotask(() { |
| 345 _complete(value); | 348 _complete(value); |
| 346 }); | 349 }); |
| 347 } | 350 } |
| 348 | 351 |
| 349 void _asyncCompleteError(error, [StackTrace stackTrace]) { | 352 void _asyncCompleteError(error, [StackTrace stackTrace]) { |
| 350 assert(!_isComplete); | 353 assert(!_isComplete); |
| 351 assert(_onValue == null); | 354 assert(_onValue == null); |
| 352 assert(_onError == null); | 355 assert(_onError == null); |
| 353 assert(_whenCompleteAction == null); | 356 assert(_whenCompleteAction == null); |
| 354 assert(_errorTest == null); | 357 assert(_errorTest == null); |
| 355 | 358 |
| 356 _markPendingCompletion(); | 359 _markPendingCompletion(); |
| 357 runAsync(() { | 360 _zone.scheduleMicrotask(() { |
| 358 _completeError(error, stackTrace); | 361 _completeError(error, stackTrace); |
| 359 }); | 362 }); |
| 360 } | 363 } |
| 361 | 364 |
| 362 /** | 365 /** |
| 363 * Propagates the value/error of [source] to its [listeners]. | 366 * Propagates the value/error of [source] to its [listeners]. |
| 364 * | 367 * |
| 365 * Unlinks all listeners and propagates the source to each listener | 368 * Unlinks all listeners and propagates the source to each listener |
| 366 * separately. | 369 * separately. |
| 367 */ | 370 */ |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 398 // Usually futures only have one listener. If they have several, we | 401 // Usually futures only have one listener. If they have several, we |
| 399 // handle them specially. | 402 // handle them specially. |
| 400 _propagateMultipleListeners(source, listeners); | 403 _propagateMultipleListeners(source, listeners); |
| 401 return; | 404 return; |
| 402 } | 405 } |
| 403 if (hasError && !source._zone.inSameErrorZone(listener._zone)) { | 406 if (hasError && !source._zone.inSameErrorZone(listener._zone)) { |
| 404 // Don't cross zone boundaries with errors. | 407 // Don't cross zone boundaries with errors. |
| 405 source._zone.handleUncaughtError(source._error); | 408 source._zone.handleUncaughtError(source._error); |
| 406 return; | 409 return; |
| 407 } | 410 } |
| 408 if (!identical(_Zone.current, listener._zone)) { | 411 if (!identical(Zone.current, listener._zone)) { |
| 409 // Run the propagation in the listener's zone to avoid | 412 // Run the propagation in the listener's zone to avoid |
| 410 // zone transitions. The idea is that many chained futures will | 413 // zone transitions. The idea is that many chained futures will |
| 411 // be in the same zone. | 414 // be in the same zone. |
| 412 listener._zone.executePeriodicCallback(() { | 415 listener._zone.run(() { |
| 413 _propagateToListeners(source, listener); | 416 _propagateToListeners(source, listener); |
| 414 }); | 417 }); |
| 415 return; | 418 return; |
| 416 } | 419 } |
| 417 | 420 |
| 418 // Do the actual propagation. | 421 // Do the actual propagation. |
| 419 // TODO(floitsch): Do we need to go through the zone even if we | 422 // TODO(floitsch): Do we need to go through the zone even if we |
| 420 // don't have a callback to execute? | 423 // don't have a callback to execute? |
| 421 bool listenerHasValue; | 424 bool listenerHasValue; |
| 422 var listenerValueOrError; | 425 var listenerValueOrError; |
| 423 // Set to true if a whenComplete needs to wait for a future. | 426 // Set to true if a whenComplete needs to wait for a future. |
| 424 // The whenComplete action will resume the propagation by itself. | 427 // The whenComplete action will resume the propagation by itself. |
| 425 bool isPropagationAborted = false; | 428 bool isPropagationAborted = false; |
| 426 // Even though we are already in the right zone (due to the optimization | 429 // Even though we are already in the right zone (due to the optimization |
| 427 // above), we still need to go through the zone. The overhead of | 430 // above), we still need to go through the zone. The overhead of |
| 428 // executeCallback is however smaller when it is already in the correct | 431 // executeCallback is however smaller when it is already in the correct |
| 429 // zone. | 432 // zone. |
| 430 // TODO(floitsch): only run callbacks in the zone, not the whole | 433 // TODO(floitsch): only run callbacks in the zone, not the whole |
| 431 // handling code. | 434 // handling code. |
| 432 listener._zone.executeCallback(() { | 435 listener._zone.run(() { |
| 433 // TODO(floitsch): mark the listener as pending completion. Currently | 436 // TODO(floitsch): mark the listener as pending completion. Currently |
| 434 // we can't do this, since the markPendingCompletion verifies that | 437 // we can't do this, since the markPendingCompletion verifies that |
| 435 // the future is not already marked (or chained). | 438 // the future is not already marked (or chained). |
| 436 try { | 439 try { |
| 437 if (!hasError) { | 440 if (!hasError) { |
| 438 var value = source._value; | 441 var value = source._value; |
| 439 if (listener._onValue != null) { | 442 if (listener._onValue != null) { |
| 440 listenerValueOrError = listener._onValue(value); | 443 listenerValueOrError = listener._onValue(value); |
| 441 listenerHasValue = true; | 444 listenerHasValue = true; |
| 442 } else { | 445 } else { |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 472 // When there is an error, we have to make the error the new | 475 // When there is an error, we have to make the error the new |
| 473 // result of the current listener. | 476 // result of the current listener. |
| 474 if (completeResult is! _Future) { | 477 if (completeResult is! _Future) { |
| 475 // This should be a rare case. | 478 // This should be a rare case. |
| 476 completeResult = new _Future(); | 479 completeResult = new _Future(); |
| 477 completeResult._setError(error); | 480 completeResult._setError(error); |
| 478 } | 481 } |
| 479 _propagateToListeners(completeResult, listener); | 482 _propagateToListeners(completeResult, listener); |
| 480 }); | 483 }); |
| 481 isPropagationAborted = true; | 484 isPropagationAborted = true; |
| 482 // We will reenter the listener's zone. | |
| 483 listener._zone.expectCallback(); | |
| 484 } | 485 } |
| 485 } | 486 } |
| 486 } catch (e, s) { | 487 } catch (e, s) { |
| 487 // Set the exception as error. | 488 // Set the exception as error. |
| 488 listenerValueOrError = _asyncError(e, s); | 489 listenerValueOrError = _asyncError(e, s); |
| 489 listenerHasValue = false; | 490 listenerHasValue = false; |
| 490 } | 491 } |
| 491 if (listenerHasValue && listenerValueOrError is Future) { | |
| 492 // We are going to reenter the zone to finish what we started. | |
| 493 listener._zone.expectCallback(); | |
| 494 } | |
| 495 }); | 492 }); |
| 496 if (isPropagationAborted) return; | 493 if (isPropagationAborted) return; |
| 497 // If the listener's value is a future we need to chain it. | 494 // If the listener's value is a future we need to chain it. |
| 498 if (listenerHasValue && listenerValueOrError is Future) { | 495 if (listenerHasValue && listenerValueOrError is Future) { |
| 499 Future chainSource = listenerValueOrError; | 496 Future chainSource = listenerValueOrError; |
| 500 // Shortcut if the chain-source is already completed. Just continue the | 497 // Shortcut if the chain-source is already completed. Just continue the |
| 501 // loop. | 498 // loop. |
| 502 if (chainSource is _Future && (chainSource as _Future)._isComplete) { | 499 if (chainSource is _Future && (chainSource as _Future)._isComplete) { |
| 503 // propagate the value (simulating a tail call). | 500 // propagate the value (simulating a tail call). |
| 504 listener._isChained = true; | 501 listener._isChained = true; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 515 listener._setValue(listenerValueOrError); | 512 listener._setValue(listenerValueOrError); |
| 516 } else { | 513 } else { |
| 517 listeners = listener._removeListeners(); | 514 listeners = listener._removeListeners(); |
| 518 listener._setError(listenerValueOrError); | 515 listener._setError(listenerValueOrError); |
| 519 } | 516 } |
| 520 // Prepare for next round. | 517 // Prepare for next round. |
| 521 source = listener; | 518 source = listener; |
| 522 } | 519 } |
| 523 } | 520 } |
| 524 } | 521 } |
| OLD | NEW |