Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: sdk/lib/async/future_impl.dart

Issue 23875032: Expose Zones. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Users can't customize runGuarded. More tests. Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 _onErrorCallback = null, _whenCompleteActionCallback = null { 148 _onErrorCallback = null, _whenCompleteActionCallback = null {
149 _asyncComplete(value); 149 _asyncComplete(value);
150 } 150 }
151 151
152 _Future.immediateError(var error, [Object stackTrace]) 152 _Future.immediateError(var error, [Object stackTrace])
153 : _onValueCallback = null, _errorTestCallback = null, 153 : _onValueCallback = null, _errorTestCallback = null,
154 _onErrorCallback = null, _whenCompleteActionCallback = null { 154 _onErrorCallback = null, _whenCompleteActionCallback = null {
155 _asyncCompleteError(error, stackTrace); 155 _asyncCompleteError(error, stackTrace);
156 } 156 }
157 157
158 _Future._then(this._onValueCallback, this._onErrorCallback) 158 _Future._then(onValueCallback(value), onErrorCallback(e))
159 : _errorTestCallback = null, _whenCompleteActionCallback = null { 159 : _onValueCallback = Zone._current.registerCallback1(onValueCallback),
160 _zone.expectCallback(); 160 _onErrorCallback = Zone._current.registerCallback1(onErrorCallback),
161 } 161 _errorTestCallback = null,
162 _whenCompleteActionCallback = null;
162 163
163 _Future._catchError(this._onErrorCallback, this._errorTestCallback) 164 _Future._catchError(onErrorCallback(e), bool errorTestCallback(e))
164 : _onValueCallback = null, _whenCompleteActionCallback = null { 165 : _onErrorCallback = Zone._current.registerCallback1(onErrorCallback),
165 _zone.expectCallback(); 166 _errorTestCallback = Zone._current.registerCallback1(errorTestCallback),
166 } 167 _onValueCallback = null,
168 _whenCompleteActionCallback = null;
167 169
168 _Future._whenComplete(this._whenCompleteActionCallback) 170 _Future._whenComplete(whenCompleteActionCallback())
169 : _onValueCallback = null, _errorTestCallback = null, 171 : _whenCompleteActionCallback =
170 _onErrorCallback = null { 172 Zone._current.registerCallback(whenCompleteActionCallback),
171 _zone.expectCallback(); 173 _onValueCallback = null,
172 } 174 _errorTestCallback = null,
175 _onErrorCallback = null;
173 176
174 Future then(f(T value), { onError(error) }) { 177 Future then(f(T value), { onError(error) }) {
175 _Future result; 178 _Future result;
176 result = new _Future._then(f, onError); 179 result = new _Future._then(f, onError);
177 _addListener(result); 180 _addListener(result);
178 return result; 181 return result;
179 } 182 }
180 183
181 Future catchError(f(error), { bool test(error) }) { 184 Future catchError(f(error), { bool test(error) }) {
182 _Future result = new _Future._catchError(f, test); 185 _Future result = new _Future._catchError(f, test);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 void _setError(Object error) { 219 void _setError(Object error) {
217 assert(!_isComplete); // But may have a completion pending. 220 assert(!_isComplete); // But may have a completion pending.
218 _state = _ERROR; 221 _state = _ERROR;
219 _resultOrListeners = error; 222 _resultOrListeners = error;
220 } 223 }
221 224
222 void _addListener(_Future listener) { 225 void _addListener(_Future listener) {
223 assert(listener._nextListener == null); 226 assert(listener._nextListener == null);
224 if (_isComplete) { 227 if (_isComplete) {
225 // Handle late listeners asynchronously. 228 // Handle late listeners asynchronously.
226 runAsync(() { 229 _zone.runAsync(() {
227 _propagateToListeners(this, listener); 230 _propagateToListeners(this, listener);
228 }); 231 });
229 } else { 232 } else {
230 listener._nextListener = _resultOrListeners; 233 listener._nextListener = _resultOrListeners;
231 _resultOrListeners = listener; 234 _resultOrListeners = listener;
232 } 235 }
233 } 236 }
234 237
235 _Future _removeListeners() { 238 _Future _removeListeners() {
236 // Reverse listeners before returning them, so the resulting list is in 239 // Reverse listeners before returning them, so the resulting list is in
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
325 (value is! _Future || !(value as _Future)._isComplete)) { 328 (value is! _Future || !(value as _Future)._isComplete)) {
326 // Case 2 from above. We need to register. 329 // Case 2 from above. We need to register.
327 // Note that we are still completing asynchronously: either we register 330 // Note that we are still completing asynchronously: either we register
328 // through .then (in which case the completing is asynchronous), or we 331 // through .then (in which case the completing is asynchronous), or we
329 // have a _Future which isn't complete yet. 332 // have a _Future which isn't complete yet.
330 _complete(value); 333 _complete(value);
331 return; 334 return;
332 } 335 }
333 336
334 _markPendingCompletion(); 337 _markPendingCompletion();
335 runAsync(() { 338 _zone.runAsync(() {
336 _complete(value); 339 _complete(value);
337 }); 340 });
338 } 341 }
339 342
340 void _asyncCompleteError(error, [StackTrace stackTrace]) { 343 void _asyncCompleteError(error, [StackTrace stackTrace]) {
341 assert(!_isComplete); 344 assert(!_isComplete);
342 assert(_onValue == null); 345 assert(_onValue == null);
343 assert(_onError == null); 346 assert(_onError == null);
344 assert(_whenCompleteAction == null); 347 assert(_whenCompleteAction == null);
345 assert(_errorTest == null); 348 assert(_errorTest == null);
346 349
347 _markPendingCompletion(); 350 _markPendingCompletion();
348 runAsync(() { 351 _zone.runAsync(() {
349 _completeError(error, stackTrace); 352 _completeError(error, stackTrace);
350 }); 353 });
351 } 354 }
352 355
353 /** 356 /**
354 * Propagates the value/error of [source] to its [listeners]. 357 * Propagates the value/error of [source] to its [listeners].
355 * 358 *
356 * Unlinks all listeners and propagates the source to each listener 359 * Unlinks all listeners and propagates the source to each listener
357 * separately. 360 * separately.
358 */ 361 */
(...skipping 30 matching lines...) Expand all
389 // Usually futures only have one listener. If they have several, we 392 // Usually futures only have one listener. If they have several, we
390 // handle them specially. 393 // handle them specially.
391 _propagateMultipleListeners(source, listeners); 394 _propagateMultipleListeners(source, listeners);
392 return; 395 return;
393 } 396 }
394 if (hasError && !source._zone.inSameErrorZone(listener._zone)) { 397 if (hasError && !source._zone.inSameErrorZone(listener._zone)) {
395 // Don't cross zone boundaries with errors. 398 // Don't cross zone boundaries with errors.
396 source._zone.handleUncaughtError(source._error); 399 source._zone.handleUncaughtError(source._error);
397 return; 400 return;
398 } 401 }
399 if (!identical(_Zone.current, listener._zone)) { 402 if (!identical(Zone.current, listener._zone)) {
400 // Run the propagation in the listener's zone to avoid 403 // Run the propagation in the listener's zone to avoid
401 // zone transitions. The idea is that many chained futures will 404 // zone transitions. The idea is that many chained futures will
402 // be in the same zone. 405 // be in the same zone.
403 listener._zone.executePeriodicCallback(() { 406 listener._zone.run(() {
404 _propagateToListeners(source, listener); 407 _propagateToListeners(source, listener);
405 }); 408 });
406 return; 409 return;
407 } 410 }
408 411
409 // Do the actual propagation. 412 // Do the actual propagation.
410 // TODO(floitsch): Do we need to go through the zone even if we 413 // TODO(floitsch): Do we need to go through the zone even if we
411 // don't have a callback to execute? 414 // don't have a callback to execute?
412 bool listenerHasValue; 415 bool listenerHasValue;
413 var listenerValueOrError; 416 var listenerValueOrError;
414 // Set to true if a whenComplete needs to wait for a future. 417 // Set to true if a whenComplete needs to wait for a future.
415 // The whenComplete action will resume the propagation by itself. 418 // The whenComplete action will resume the propagation by itself.
416 bool isPropagationAborted = false; 419 bool isPropagationAborted = false;
417 // Even though we are already in the right zone (due to the optimization 420 // Even though we are already in the right zone (due to the optimization
418 // above), we still need to go through the zone. The overhead of 421 // above), we still need to go through the zone. The overhead of
419 // executeCallback is however smaller when it is already in the correct 422 // executeCallback is however smaller when it is already in the correct
420 // zone. 423 // zone.
421 // TODO(floitsch): only run callbacks in the zone, not the whole 424 // TODO(floitsch): only run callbacks in the zone, not the whole
422 // handling code. 425 // handling code.
423 listener._zone.executeCallback(() { 426 listener._zone.run(() {
424 // TODO(floitsch): mark the listener as pending completion. Currently 427 // TODO(floitsch): mark the listener as pending completion. Currently
425 // we can't do this, since the markPendingCompletion verifies that 428 // we can't do this, since the markPendingCompletion verifies that
426 // the future is not already marked (or chained). 429 // the future is not already marked (or chained).
427 try { 430 try {
428 if (!hasError) { 431 if (!hasError) {
429 var value = source._value; 432 var value = source._value;
430 if (listener._onValue != null) { 433 if (listener._onValue != null) {
431 listenerValueOrError = listener._onValue(value); 434 listenerValueOrError = listener._onValue(value);
432 listenerHasValue = true; 435 listenerHasValue = true;
433 } else { 436 } else {
(...skipping 29 matching lines...) Expand all
463 // When there is an error, we have to make the error the new 466 // When there is an error, we have to make the error the new
464 // result of the current listener. 467 // result of the current listener.
465 if (completeResult is! _Future) { 468 if (completeResult is! _Future) {
466 // This should be a rare case. 469 // This should be a rare case.
467 completeResult = new _Future(); 470 completeResult = new _Future();
468 completeResult._setError(error); 471 completeResult._setError(error);
469 } 472 }
470 _propagateToListeners(completeResult, listener); 473 _propagateToListeners(completeResult, listener);
471 }); 474 });
472 isPropagationAborted = true; 475 isPropagationAborted = true;
473 // We will reenter the listener's zone.
474 listener._zone.expectCallback();
475 } 476 }
476 } 477 }
477 } catch (e, s) { 478 } catch (e, s) {
478 // Set the exception as error. 479 // Set the exception as error.
479 listenerValueOrError = _asyncError(e, s); 480 listenerValueOrError = _asyncError(e, s);
480 listenerHasValue = false; 481 listenerHasValue = false;
481 } 482 }
482 if (listenerHasValue && listenerValueOrError is Future) {
483 // We are going to reenter the zone to finish what we started.
484 listener._zone.expectCallback();
485 }
486 }); 483 });
487 if (isPropagationAborted) return; 484 if (isPropagationAborted) return;
488 // If the listener's value is a future we need to chain it. 485 // If the listener's value is a future we need to chain it.
489 if (listenerHasValue && listenerValueOrError is Future) { 486 if (listenerHasValue && listenerValueOrError is Future) {
490 Future chainSource = listenerValueOrError; 487 Future chainSource = listenerValueOrError;
491 // Shortcut if the chain-source is already completed. Just continue the 488 // Shortcut if the chain-source is already completed. Just continue the
492 // loop. 489 // loop.
493 if (chainSource is _Future && (chainSource as _Future)._isComplete) { 490 if (chainSource is _Future && (chainSource as _Future)._isComplete) {
494 // propagate the value (simulating a tail call). 491 // propagate the value (simulating a tail call).
495 listener._isChained = true; 492 listener._isChained = true;
(...skipping 10 matching lines...) Expand all
506 listener._setValue(listenerValueOrError); 503 listener._setValue(listenerValueOrError);
507 } else { 504 } else {
508 listeners = listener._removeListeners(); 505 listeners = listener._removeListeners();
509 listener._setError(listenerValueOrError); 506 listener._setError(listenerValueOrError);
510 } 507 }
511 // Prepare for next round. 508 // Prepare for next round.
512 source = listener; 509 source = listener;
513 } 510 }
514 } 511 }
515 } 512 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698