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); | |
10 /** Test used by [Future.catchError] to handle skip some errors. */ | 9 /** Test used by [Future.catchError] to handle skip some errors. */ |
11 typedef bool _FutureErrorTest(var error); | 10 typedef bool _FutureErrorTest(var error); |
12 /** Used by [WhenFuture]. */ | 11 /** Used by [WhenFuture]. */ |
13 typedef _FutureAction(); | 12 typedef _FutureAction(); |
14 | 13 |
15 abstract class _Completer<T> implements Completer<T> { | 14 abstract class _Completer<T> implements Completer<T> { |
16 final _Future<T> future = new _Future<T>(); | 15 final _Future<T> future = new _Future<T>(); |
17 | 16 |
18 void complete([T value]); | 17 void complete([T value]); |
19 | 18 |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 // TODO(floitsch): since single listeners are the common case we should | 122 // TODO(floitsch): since single listeners are the common case we should |
124 // use a bit to indicate that the _resultOrListeners contains a container. | 123 // use a bit to indicate that the _resultOrListeners contains a container. |
125 _Future _nextListener; | 124 _Future _nextListener; |
126 | 125 |
127 // TODO(floitsch): we only need two closure fields to store the callbacks. | 126 // TODO(floitsch): we only need two closure fields to store the callbacks. |
128 // If we store the type of a closure in the state field (where there are | 127 // If we store the type of a closure in the state field (where there are |
129 // still bits left), we can just store two closures instead of using 4 | 128 // still bits left), we can just store two closures instead of using 4 |
130 // fields of which 2 are always null. | 129 // fields of which 2 are always null. |
131 final _FutureOnValue _onValueCallback; | 130 final _FutureOnValue _onValueCallback; |
132 final _FutureErrorTest _errorTestCallback; | 131 final _FutureErrorTest _errorTestCallback; |
133 final _FutureOnError _onErrorCallback; | 132 final Function _onErrorCallback; |
134 final _FutureAction _whenCompleteActionCallback; | 133 final _FutureAction _whenCompleteActionCallback; |
135 | 134 |
136 _FutureOnValue get _onValue => _isChained ? null : _onValueCallback; | 135 _FutureOnValue get _onValue => _isChained ? null : _onValueCallback; |
137 _FutureErrorTest get _errorTest => _isChained ? null : _errorTestCallback; | 136 _FutureErrorTest get _errorTest => _isChained ? null : _errorTestCallback; |
138 _FutureOnError get _onError => _isChained ? null : _onErrorCallback; | 137 Function get _onError => _isChained ? null : _onErrorCallback; |
139 _FutureAction get _whenCompleteAction | 138 _FutureAction get _whenCompleteAction |
140 => _isChained ? null : _whenCompleteActionCallback; | 139 => _isChained ? null : _whenCompleteActionCallback; |
141 | 140 |
142 _Future() | 141 _Future() |
143 : _zone = Zone.current, | 142 : _zone = Zone.current, |
144 _onValueCallback = null, _errorTestCallback = null, | 143 _onValueCallback = null, _errorTestCallback = null, |
145 _onErrorCallback = null, _whenCompleteActionCallback = null; | 144 _onErrorCallback = null, _whenCompleteActionCallback = null; |
146 | 145 |
147 /// Valid types for value: `T` or `Future<T>`. | 146 /// Valid types for value: `T` or `Future<T>`. |
148 _Future.immediate(value) | 147 _Future.immediate(value) |
149 : _zone = Zone.current, | 148 : _zone = Zone.current, |
150 _onValueCallback = null, _errorTestCallback = null, | 149 _onValueCallback = null, _errorTestCallback = null, |
151 _onErrorCallback = null, _whenCompleteActionCallback = null { | 150 _onErrorCallback = null, _whenCompleteActionCallback = null { |
152 _asyncComplete(value); | 151 _asyncComplete(value); |
153 } | 152 } |
154 | 153 |
155 _Future.immediateError(var error, [Object stackTrace]) | 154 _Future.immediateError(var error, [Object stackTrace]) |
156 : _zone = Zone.current, | 155 : _zone = Zone.current, |
157 _onValueCallback = null, _errorTestCallback = null, | 156 _onValueCallback = null, _errorTestCallback = null, |
158 _onErrorCallback = null, _whenCompleteActionCallback = null { | 157 _onErrorCallback = null, _whenCompleteActionCallback = null { |
159 _asyncCompleteError(error, stackTrace); | 158 _asyncCompleteError(error, stackTrace); |
160 } | 159 } |
161 | 160 |
162 _Future._then(onValueCallback(value), onErrorCallback(e)) | 161 _Future._then(onValueCallback(value), Function onErrorCallback) |
163 : _zone = Zone.current, | 162 : _zone = Zone.current, |
164 _onValueCallback = Zone.current.registerUnaryCallback(onValueCallback), | 163 _onValueCallback = Zone.current.registerUnaryCallback(onValueCallback), |
165 _onErrorCallback = Zone.current.registerUnaryCallback(onErrorCallback), | 164 _onErrorCallback = _registerErrorCallback(onErrorCallback), |
166 _errorTestCallback = null, | 165 _errorTestCallback = null, |
167 _whenCompleteActionCallback = null; | 166 _whenCompleteActionCallback = null; |
168 | 167 |
169 _Future._catchError(onErrorCallback(e), bool errorTestCallback(e)) | 168 _Future._catchError(Function onErrorCallback, bool errorTestCallback(e)) |
170 : _zone = Zone.current, | 169 : _zone = Zone.current, |
171 _onErrorCallback = Zone.current.registerUnaryCallback(onErrorCallback), | 170 _onErrorCallback = _registerErrorCallback(onErrorCallback), |
172 _errorTestCallback = Zone.current.registerUnaryCallback(errorTestCallback)
, | 171 _errorTestCallback = |
| 172 Zone.current.registerUnaryCallback(errorTestCallback), |
173 _onValueCallback = null, | 173 _onValueCallback = null, |
174 _whenCompleteActionCallback = null; | 174 _whenCompleteActionCallback = null; |
175 | 175 |
176 _Future._whenComplete(whenCompleteActionCallback()) | 176 _Future._whenComplete(whenCompleteActionCallback()) |
177 : _zone = Zone.current, | 177 : _zone = Zone.current, |
178 _whenCompleteActionCallback = | 178 _whenCompleteActionCallback = |
179 Zone.current.registerCallback(whenCompleteActionCallback), | 179 Zone.current.registerCallback(whenCompleteActionCallback), |
180 _onValueCallback = null, | 180 _onValueCallback = null, |
181 _errorTestCallback = null, | 181 _errorTestCallback = null, |
182 _onErrorCallback = null; | 182 _onErrorCallback = null; |
183 | 183 |
184 Future then(f(T value), { onError(error) }) { | 184 /// Register the given [errorCallback] in the current zone. |
| 185 static Function _registerErrorCallback(Function errorCallback) { |
| 186 if (errorCallback is ZoneBinaryCallback) { |
| 187 return Zone.current.registerBinaryCallback(errorCallback); |
| 188 } else { |
| 189 return Zone.current.registerUnaryCallback(errorCallback); |
| 190 } |
| 191 } |
| 192 |
| 193 Future then(f(T value), { Function onError }) { |
185 _Future result; | 194 _Future result; |
186 result = new _Future._then(f, onError); | 195 result = new _Future._then(f, onError); |
187 _addListener(result); | 196 _addListener(result); |
188 return result; | 197 return result; |
189 } | 198 } |
190 | 199 |
191 Future catchError(f(error), { bool test(error) }) { | 200 Future catchError(Function onError, { bool test(error) }) { |
192 _Future result = new _Future._catchError(f, test); | 201 _Future result = new _Future._catchError(onError, test); |
193 _addListener(result); | 202 _addListener(result); |
194 return result; | 203 return result; |
195 } | 204 } |
196 | 205 |
197 Future<T> whenComplete(action()) { | 206 Future<T> whenComplete(action()) { |
198 _Future result = new _Future<T>._whenComplete(action); | 207 _Future result = new _Future<T>._whenComplete(action); |
199 _addListener(result); | 208 _addListener(result); |
200 return result; | 209 return result; |
201 } | 210 } |
202 | 211 |
203 Stream<T> asStream() => new Stream.fromFuture(this); | 212 Stream<T> asStream() => new Stream.fromFuture(this); |
204 | 213 |
205 void _markPendingCompletion() { | 214 void _markPendingCompletion() { |
206 if (!_mayComplete) throw new StateError("Future already completed"); | 215 if (!_mayComplete) throw new StateError("Future already completed"); |
207 _state = _PENDING_COMPLETE; | 216 _state = _PENDING_COMPLETE; |
208 } | 217 } |
209 | 218 |
210 T get _value { | 219 T get _value { |
211 assert(_isComplete && _hasValue); | 220 assert(_isComplete && _hasValue); |
212 return _resultOrListeners; | 221 return _resultOrListeners; |
213 } | 222 } |
214 | 223 |
215 Object get _error { | 224 _AsyncError get _error { |
216 assert(_isComplete && _hasError); | 225 assert(_isComplete && _hasError); |
217 return _resultOrListeners; | 226 return _resultOrListeners; |
218 } | 227 } |
219 | 228 |
220 void _setValue(T value) { | 229 void _setValue(T value) { |
221 assert(!_isComplete); // But may have a completion pending. | 230 assert(!_isComplete); // But may have a completion pending. |
222 _state = _VALUE; | 231 _state = _VALUE; |
223 _resultOrListeners = value; | 232 _resultOrListeners = value; |
224 } | 233 } |
225 | 234 |
226 void _setError(Object error) { | 235 void _setError(Object error, StackTrace stackTrace) { |
227 assert(!_isComplete); // But may have a completion pending. | 236 assert(!_isComplete); // But may have a completion pending. |
228 _state = _ERROR; | 237 _state = _ERROR; |
229 _resultOrListeners = error; | 238 _resultOrListeners = new _AsyncError(error, stackTrace); |
230 } | 239 } |
231 | 240 |
232 void _addListener(_Future listener) { | 241 void _addListener(_Future listener) { |
233 assert(listener._nextListener == null); | 242 assert(listener._nextListener == null); |
234 if (_isComplete) { | 243 if (_isComplete) { |
235 // Handle late listeners asynchronously. | 244 // Handle late listeners asynchronously. |
236 _zone.scheduleMicrotask(() { | 245 _zone.scheduleMicrotask(() { |
237 _propagateToListeners(this, listener); | 246 _propagateToListeners(this, listener); |
238 }); | 247 }); |
239 } else { | 248 } else { |
(...skipping 28 matching lines...) Expand all Loading... |
268 if (internalFuture._isComplete) { | 277 if (internalFuture._isComplete) { |
269 _propagateToListeners(internalFuture, target); | 278 _propagateToListeners(internalFuture, target); |
270 } else { | 279 } else { |
271 internalFuture._addListener(target); | 280 internalFuture._addListener(target); |
272 } | 281 } |
273 } else { | 282 } else { |
274 source.then((value) { | 283 source.then((value) { |
275 assert(target._isChained); | 284 assert(target._isChained); |
276 target._complete(value); | 285 target._complete(value); |
277 }, | 286 }, |
278 onError: (error) { | 287 // TODO(floitsch): eventually we would like to make this non-optional |
| 288 // and dependent on the listeners of the target future. If none of |
| 289 // the target future's listeners want to have the stack trace we don't |
| 290 // need a trace. |
| 291 onError: (error, [stackTrace]) { |
279 assert(target._isChained); | 292 assert(target._isChained); |
280 target._completeError(error); | 293 target._completeError(error, stackTrace); |
281 }); | 294 }); |
282 } | 295 } |
283 } | 296 } |
284 | 297 |
285 void _complete(value) { | 298 void _complete(value) { |
286 assert(!_isComplete); | 299 assert(!_isComplete); |
287 assert(_onValue == null); | 300 assert(_onValue == null); |
288 assert(_onError == null); | 301 assert(_onError == null); |
289 assert(_whenCompleteAction == null); | 302 assert(_whenCompleteAction == null); |
290 assert(_errorTest == null); | 303 assert(_errorTest == null); |
(...skipping 13 matching lines...) Expand all Loading... |
304 assert(_onError == null); | 317 assert(_onError == null); |
305 assert(_whenCompleteAction == null); | 318 assert(_whenCompleteAction == null); |
306 assert(_errorTest == null); | 319 assert(_errorTest == null); |
307 | 320 |
308 if (stackTrace != null) { | 321 if (stackTrace != null) { |
309 // Force the stack trace onto the error, even if it already had one. | 322 // Force the stack trace onto the error, even if it already had one. |
310 _attachStackTrace(error, stackTrace); | 323 _attachStackTrace(error, stackTrace); |
311 } | 324 } |
312 | 325 |
313 _Future listeners = _isChained ? null : _removeListeners(); | 326 _Future listeners = _isChained ? null : _removeListeners(); |
314 _setError(error); | 327 _setError(error, stackTrace); |
315 _propagateToListeners(this, listeners); | 328 _propagateToListeners(this, listeners); |
316 } | 329 } |
317 | 330 |
318 void _asyncComplete(value) { | 331 void _asyncComplete(value) { |
319 assert(!_isComplete); | 332 assert(!_isComplete); |
320 assert(_onValue == null); | 333 assert(_onValue == null); |
321 assert(_onError == null); | 334 assert(_onError == null); |
322 assert(_whenCompleteAction == null); | 335 assert(_whenCompleteAction == null); |
323 assert(_errorTest == null); | 336 assert(_errorTest == null); |
324 // Two corner cases if the value is a future: | 337 // Two corner cases if the value is a future: |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
391 * | 404 * |
392 * If [runCallback] is true (which should be the default) it executes | 405 * If [runCallback] is true (which should be the default) it executes |
393 * the registered action of listeners. If it is `false` then the callback is | 406 * the registered action of listeners. If it is `false` then the callback is |
394 * skipped. This is used to complete futures with chained futures. | 407 * skipped. This is used to complete futures with chained futures. |
395 */ | 408 */ |
396 static void _propagateToListeners(_Future source, _Future listeners) { | 409 static void _propagateToListeners(_Future source, _Future listeners) { |
397 while (true) { | 410 while (true) { |
398 if (!source._isComplete) return; // Chained future. | 411 if (!source._isComplete) return; // Chained future. |
399 bool hasError = source._hasError; | 412 bool hasError = source._hasError; |
400 if (hasError && listeners == null) { | 413 if (hasError && listeners == null) { |
401 source._zone.handleUncaughtError(source._error); | 414 _AsyncError asyncError = source._error; |
| 415 source._zone.handleUncaughtError( |
| 416 asyncError.error, asyncError.stackTrace); |
402 return; | 417 return; |
403 } | 418 } |
404 if (listeners == null) return; | 419 if (listeners == null) return; |
405 _Future listener = listeners; | 420 _Future listener = listeners; |
406 if (listener._nextListener != null) { | 421 if (listener._nextListener != null) { |
407 // Usually futures only have one listener. If they have several, we | 422 // Usually futures only have one listener. If they have several, we |
408 // handle them specially. | 423 // handle them specially. |
409 _propagateMultipleListeners(source, listeners); | 424 _propagateMultipleListeners(source, listeners); |
410 return; | 425 return; |
411 } | 426 } |
412 if (hasError && !source._zone.inSameErrorZone(listener._zone)) { | 427 if (hasError && !source._zone.inSameErrorZone(listener._zone)) { |
413 // Don't cross zone boundaries with errors. | 428 // Don't cross zone boundaries with errors. |
414 source._zone.handleUncaughtError(source._error); | 429 _AsyncError asyncError = source._error; |
| 430 source._zone.handleUncaughtError( |
| 431 asyncError.error, asyncError.stackTrace); |
415 return; | 432 return; |
416 } | 433 } |
417 if (!identical(Zone.current, listener._zone)) { | 434 if (!identical(Zone.current, listener._zone)) { |
418 // Run the propagation in the listener's zone to avoid | 435 // Run the propagation in the listener's zone to avoid |
419 // zone transitions. The idea is that many chained futures will | 436 // zone transitions. The idea is that many chained futures will |
420 // be in the same zone. | 437 // be in the same zone. |
421 listener._zone.run(() { | 438 listener._zone.run(() { |
422 _propagateToListeners(source, listener); | 439 _propagateToListeners(source, listener); |
423 }); | 440 }); |
424 return; | 441 return; |
(...skipping 22 matching lines...) Expand all Loading... |
447 var value = source._value; | 464 var value = source._value; |
448 if (listener._onValue != null) { | 465 if (listener._onValue != null) { |
449 listenerValueOrError = listener._onValue(value); | 466 listenerValueOrError = listener._onValue(value); |
450 listenerHasValue = true; | 467 listenerHasValue = true; |
451 } else { | 468 } else { |
452 // Copy over the value from the source. | 469 // Copy over the value from the source. |
453 listenerValueOrError = value; | 470 listenerValueOrError = value; |
454 listenerHasValue = true; | 471 listenerHasValue = true; |
455 } | 472 } |
456 } else { | 473 } else { |
457 Object error = source._error; | 474 _AsyncError asyncError = source._error; |
458 _FutureErrorTest test = listener._errorTest; | 475 _FutureErrorTest test = listener._errorTest; |
459 bool matchesTest = true; | 476 bool matchesTest = true; |
460 if (test != null) { | 477 if (test != null) { |
461 matchesTest = test(error); | 478 matchesTest = test(asyncError.error); |
462 } | 479 } |
463 if (matchesTest && listener._onError != null) { | 480 if (matchesTest && listener._onError != null) { |
464 listenerValueOrError = listener._onError(error); | 481 Function errorCallback = listener._onError; |
| 482 if (errorCallback is ZoneBinaryCallback) { |
| 483 listenerValueOrError = |
| 484 errorCallback(asyncError.error, asyncError.stackTrace); |
| 485 } else { |
| 486 listenerValueOrError = listener._onError(asyncError.error); |
| 487 } |
465 listenerHasValue = true; | 488 listenerHasValue = true; |
466 } else { | 489 } else { |
467 // Copy over the error from the source. | 490 // Copy over the error from the source. |
468 listenerValueOrError = error; | 491 listenerValueOrError = asyncError; |
469 listenerHasValue = false; | 492 listenerHasValue = false; |
470 } | 493 } |
471 } | 494 } |
472 | 495 |
473 if (listener._whenCompleteAction != null) { | 496 if (listener._whenCompleteAction != null) { |
474 var completeResult = listener._whenCompleteAction(); | 497 var completeResult = listener._whenCompleteAction(); |
475 if (completeResult is Future) { | 498 if (completeResult is Future) { |
476 listener._isChained = true; | 499 listener._isChained = true; |
477 completeResult.then((ignored) { | 500 completeResult.then((ignored) { |
478 // Try again, but this time don't run the whenComplete callback. | 501 // Try again, but this time don't run the whenComplete callback. |
479 _propagateToListeners(source, listener); | 502 _propagateToListeners(source, listener); |
480 }, onError: (error) { | 503 }, onError: (error, [stackTrace]) { |
481 // When there is an error, we have to make the error the new | 504 // When there is an error, we have to make the error the new |
482 // result of the current listener. | 505 // result of the current listener. |
483 if (completeResult is! _Future) { | 506 if (completeResult is! _Future) { |
484 // This should be a rare case. | 507 // This should be a rare case. |
485 completeResult = new _Future(); | 508 completeResult = new _Future(); |
486 completeResult._setError(error); | 509 completeResult._setError(error, stackTrace); |
487 } | 510 } |
488 _propagateToListeners(completeResult, listener); | 511 _propagateToListeners(completeResult, listener); |
489 }); | 512 }); |
490 isPropagationAborted = true; | 513 isPropagationAborted = true; |
491 } | 514 } |
492 } | 515 } |
493 } catch (e, s) { | 516 } catch (e, s) { |
494 // Set the exception as error. | 517 // Set the exception as error unless the error is the same as the |
495 listenerValueOrError = _asyncError(e, s); | 518 // original one. |
| 519 if (hasError && identical(source._error.error, e)) { |
| 520 listenerValueOrError = source._error; |
| 521 } else { |
| 522 listenerValueOrError = new _AsyncError(_asyncError(e, s), s); |
| 523 } |
496 listenerHasValue = false; | 524 listenerHasValue = false; |
497 } | 525 } |
498 }); | 526 }); |
499 if (isPropagationAborted) return; | 527 if (isPropagationAborted) return; |
500 // If the listener's value is a future we need to chain it. | 528 // If the listener's value is a future we need to chain it. |
501 if (listenerHasValue && listenerValueOrError is Future) { | 529 if (listenerHasValue && listenerValueOrError is Future) { |
502 Future chainSource = listenerValueOrError; | 530 Future chainSource = listenerValueOrError; |
503 // Shortcut if the chain-source is already completed. Just continue the | 531 // Shortcut if the chain-source is already completed. Just continue the |
504 // loop. | 532 // loop. |
505 if (chainSource is _Future && (chainSource as _Future)._isComplete) { | 533 if (chainSource is _Future && (chainSource as _Future)._isComplete) { |
506 // propagate the value (simulating a tail call). | 534 // propagate the value (simulating a tail call). |
507 listener._isChained = true; | 535 listener._isChained = true; |
508 source = chainSource; | 536 source = chainSource; |
509 listeners = listener; | 537 listeners = listener; |
510 continue; | 538 continue; |
511 } | 539 } |
512 _chainFutures(chainSource, listener); | 540 _chainFutures(chainSource, listener); |
513 return; | 541 return; |
514 } | 542 } |
515 | 543 |
516 if (listenerHasValue) { | 544 if (listenerHasValue) { |
517 listeners = listener._removeListeners(); | 545 listeners = listener._removeListeners(); |
518 listener._setValue(listenerValueOrError); | 546 listener._setValue(listenerValueOrError); |
519 } else { | 547 } else { |
520 listeners = listener._removeListeners(); | 548 listeners = listener._removeListeners(); |
521 listener._setError(listenerValueOrError); | 549 _AsyncError asyncError = listenerValueOrError; |
| 550 listener._setError(asyncError.error, asyncError.stackTrace); |
522 } | 551 } |
523 // Prepare for next round. | 552 // Prepare for next round. |
524 source = listener; | 553 source = listener; |
525 } | 554 } |
526 } | 555 } |
527 } | 556 } |
OLD | NEW |