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

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: rebase 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
« no previous file with comments | « sdk/lib/async/future.dart ('k') | sdk/lib/async/stream_controller.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 final _FutureOnError _onErrorCallback; 133 final _FutureOnError _onErrorCallback;
134 final _FutureAction _whenCompleteActionCallback; 134 final _FutureAction _whenCompleteActionCallback;
135 135
136 _FutureOnValue get _onValue => _isChained ? null : _onValueCallback; 136 _FutureOnValue get _onValue => _isChained ? null : _onValueCallback;
137 _FutureErrorTest get _errorTest => _isChained ? null : _errorTestCallback; 137 _FutureErrorTest get _errorTest => _isChained ? null : _errorTestCallback;
138 _FutureOnError get _onError => _isChained ? null : _onErrorCallback; 138 _FutureOnError get _onError => _isChained ? null : _onErrorCallback;
139 _FutureAction get _whenCompleteAction 139 _FutureAction get _whenCompleteAction
140 => _isChained ? null : _whenCompleteActionCallback; 140 => _isChained ? null : _whenCompleteActionCallback;
141 141
142 _Future() 142 _Future()
143 : _onValueCallback = null, _errorTestCallback = null, 143 : _zone = Zone.current,
144 _onValueCallback = null, _errorTestCallback = null,
144 _onErrorCallback = null, _whenCompleteActionCallback = null; 145 _onErrorCallback = null, _whenCompleteActionCallback = null;
145 146
146 /// Valid types for value: `T` or `Future<T>`. 147 /// Valid types for value: `T` or `Future<T>`.
147 _Future.immediate(value) 148 _Future.immediate(value)
148 : _onValueCallback = null, _errorTestCallback = null, 149 : _zone = Zone.current,
150 _onValueCallback = null, _errorTestCallback = null,
149 _onErrorCallback = null, _whenCompleteActionCallback = null { 151 _onErrorCallback = null, _whenCompleteActionCallback = null {
150 _asyncComplete(value); 152 _asyncComplete(value);
151 } 153 }
152 154
153 _Future.immediateError(var error, [Object stackTrace]) 155 _Future.immediateError(var error, [Object stackTrace])
154 : _onValueCallback = null, _errorTestCallback = null, 156 : _zone = Zone.current,
157 _onValueCallback = null, _errorTestCallback = null,
155 _onErrorCallback = null, _whenCompleteActionCallback = null { 158 _onErrorCallback = null, _whenCompleteActionCallback = null {
156 _asyncCompleteError(error, stackTrace); 159 _asyncCompleteError(error, stackTrace);
157 } 160 }
158 161
159 _Future._then(this._onValueCallback, this._onErrorCallback) 162 _Future._then(onValueCallback(value), onErrorCallback(e))
160 : _errorTestCallback = null, _whenCompleteActionCallback = null { 163 : _zone = Zone.current,
161 _zone.expectCallback(); 164 _onValueCallback = Zone.current.registerUnaryCallback(onValueCallback),
162 } 165 _onErrorCallback = Zone.current.registerUnaryCallback(onErrorCallback),
166 _errorTestCallback = null,
167 _whenCompleteActionCallback = null;
163 168
164 _Future._catchError(this._onErrorCallback, this._errorTestCallback) 169 _Future._catchError(onErrorCallback(e), bool errorTestCallback(e))
165 : _onValueCallback = null, _whenCompleteActionCallback = null { 170 : _zone = Zone.current,
166 _zone.expectCallback(); 171 _onErrorCallback = Zone.current.registerUnaryCallback(onErrorCallback),
167 } 172 _errorTestCallback = Zone.current.registerUnaryCallback(errorTestCallback) ,
173 _onValueCallback = null,
174 _whenCompleteActionCallback = null;
168 175
169 _Future._whenComplete(this._whenCompleteActionCallback) 176 _Future._whenComplete(whenCompleteActionCallback())
170 : _onValueCallback = null, _errorTestCallback = null, 177 : _zone = Zone.current,
171 _onErrorCallback = null { 178 _whenCompleteActionCallback =
172 _zone.expectCallback(); 179 Zone.current.registerCallback(whenCompleteActionCallback),
173 } 180 _onValueCallback = null,
181 _errorTestCallback = null,
182 _onErrorCallback = null;
174 183
175 Future then(f(T value), { onError(error) }) { 184 Future then(f(T value), { onError(error) }) {
176 _Future result; 185 _Future result;
177 result = new _Future._then(f, onError); 186 result = new _Future._then(f, onError);
178 _addListener(result); 187 _addListener(result);
179 return result; 188 return result;
180 } 189 }
181 190
182 Future catchError(f(error), { bool test(error) }) { 191 Future catchError(f(error), { bool test(error) }) {
183 _Future result = new _Future._catchError(f, test); 192 _Future result = new _Future._catchError(f, test);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 void _setError(Object error) { 226 void _setError(Object error) {
218 assert(!_isComplete); // But may have a completion pending. 227 assert(!_isComplete); // But may have a completion pending.
219 _state = _ERROR; 228 _state = _ERROR;
220 _resultOrListeners = error; 229 _resultOrListeners = error;
221 } 230 }
222 231
223 void _addListener(_Future listener) { 232 void _addListener(_Future listener) {
224 assert(listener._nextListener == null); 233 assert(listener._nextListener == null);
225 if (_isComplete) { 234 if (_isComplete) {
226 // Handle late listeners asynchronously. 235 // Handle late listeners asynchronously.
227 _zone.runAsync(() { 236 _zone.scheduleMicrotask(() {
228 _propagateToListeners(this, listener); 237 _propagateToListeners(this, listener);
229 }, _zone); 238 });
230 } else { 239 } else {
231 listener._nextListener = _resultOrListeners; 240 listener._nextListener = _resultOrListeners;
232 _resultOrListeners = listener; 241 _resultOrListeners = listener;
233 } 242 }
234 } 243 }
235 244
236 _Future _removeListeners() { 245 _Future _removeListeners() {
237 // Reverse listeners before returning them, so the resulting list is in 246 // Reverse listeners before returning them, so the resulting list is in
238 // subscription order. 247 // subscription order.
239 assert(!_isComplete); 248 assert(!_isComplete);
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 (value is! _Future || !(value as _Future)._isComplete)) { 343 (value is! _Future || !(value as _Future)._isComplete)) {
335 // Case 2 from above. We need to register. 344 // Case 2 from above. We need to register.
336 // Note that we are still completing asynchronously: either we register 345 // Note that we are still completing asynchronously: either we register
337 // through .then (in which case the completing is asynchronous), or we 346 // through .then (in which case the completing is asynchronous), or we
338 // have a _Future which isn't complete yet. 347 // have a _Future which isn't complete yet.
339 _complete(value); 348 _complete(value);
340 return; 349 return;
341 } 350 }
342 351
343 _markPendingCompletion(); 352 _markPendingCompletion();
344 _zone.runAsync(() { _complete(value); }, _zone); 353 _zone.scheduleMicrotask(() {
354 _complete(value);
355 });
345 } 356 }
346 357
347 void _asyncCompleteError(error, [StackTrace stackTrace]) { 358 void _asyncCompleteError(error, [StackTrace stackTrace]) {
348 assert(!_isComplete); 359 assert(!_isComplete);
349 assert(_onValue == null); 360 assert(_onValue == null);
350 assert(_onError == null); 361 assert(_onError == null);
351 assert(_whenCompleteAction == null); 362 assert(_whenCompleteAction == null);
352 assert(_errorTest == null); 363 assert(_errorTest == null);
353 364
354 _markPendingCompletion(); 365 _markPendingCompletion();
355 _zone.runAsync(() { _completeError(error, stackTrace); }, _zone); 366 _zone.scheduleMicrotask(() {
367 _completeError(error, stackTrace);
368 });
356 } 369 }
357 370
358 /** 371 /**
359 * Propagates the value/error of [source] to its [listeners]. 372 * Propagates the value/error of [source] to its [listeners].
360 * 373 *
361 * Unlinks all listeners and propagates the source to each listener 374 * Unlinks all listeners and propagates the source to each listener
362 * separately. 375 * separately.
363 */ 376 */
364 static void _propagateMultipleListeners(_Future source, _Future listeners) { 377 static void _propagateMultipleListeners(_Future source, _Future listeners) {
365 assert(listeners != null); 378 assert(listeners != null);
(...skipping 28 matching lines...) Expand all
394 // Usually futures only have one listener. If they have several, we 407 // Usually futures only have one listener. If they have several, we
395 // handle them specially. 408 // handle them specially.
396 _propagateMultipleListeners(source, listeners); 409 _propagateMultipleListeners(source, listeners);
397 return; 410 return;
398 } 411 }
399 if (hasError && !source._zone.inSameErrorZone(listener._zone)) { 412 if (hasError && !source._zone.inSameErrorZone(listener._zone)) {
400 // Don't cross zone boundaries with errors. 413 // Don't cross zone boundaries with errors.
401 source._zone.handleUncaughtError(source._error); 414 source._zone.handleUncaughtError(source._error);
402 return; 415 return;
403 } 416 }
404 if (!identical(_Zone.current, listener._zone)) { 417 if (!identical(Zone.current, listener._zone)) {
405 // Run the propagation in the listener's zone to avoid 418 // Run the propagation in the listener's zone to avoid
406 // zone transitions. The idea is that many chained futures will 419 // zone transitions. The idea is that many chained futures will
407 // be in the same zone. 420 // be in the same zone.
408 listener._zone.executePeriodicCallback(() { 421 listener._zone.run(() {
409 _propagateToListeners(source, listener); 422 _propagateToListeners(source, listener);
410 }); 423 });
411 return; 424 return;
412 } 425 }
413 426
414 // Do the actual propagation. 427 // Do the actual propagation.
415 // TODO(floitsch): Do we need to go through the zone even if we 428 // TODO(floitsch): Do we need to go through the zone even if we
416 // don't have a callback to execute? 429 // don't have a callback to execute?
417 bool listenerHasValue; 430 bool listenerHasValue;
418 var listenerValueOrError; 431 var listenerValueOrError;
419 // Set to true if a whenComplete needs to wait for a future. 432 // Set to true if a whenComplete needs to wait for a future.
420 // The whenComplete action will resume the propagation by itself. 433 // The whenComplete action will resume the propagation by itself.
421 bool isPropagationAborted = false; 434 bool isPropagationAborted = false;
422 // Even though we are already in the right zone (due to the optimization 435 // Even though we are already in the right zone (due to the optimization
423 // above), we still need to go through the zone. The overhead of 436 // above), we still need to go through the zone. The overhead of
424 // executeCallback is however smaller when it is already in the correct 437 // executeCallback is however smaller when it is already in the correct
425 // zone. 438 // zone.
426 // TODO(floitsch): only run callbacks in the zone, not the whole 439 // TODO(floitsch): only run callbacks in the zone, not the whole
427 // handling code. 440 // handling code.
428 listener._zone.executeCallback(() { 441 listener._zone.run(() {
429 // TODO(floitsch): mark the listener as pending completion. Currently 442 // TODO(floitsch): mark the listener as pending completion. Currently
430 // we can't do this, since the markPendingCompletion verifies that 443 // we can't do this, since the markPendingCompletion verifies that
431 // the future is not already marked (or chained). 444 // the future is not already marked (or chained).
432 try { 445 try {
433 if (!hasError) { 446 if (!hasError) {
434 var value = source._value; 447 var value = source._value;
435 if (listener._onValue != null) { 448 if (listener._onValue != null) {
436 listenerValueOrError = listener._onValue(value); 449 listenerValueOrError = listener._onValue(value);
437 listenerHasValue = true; 450 listenerHasValue = true;
438 } else { 451 } else {
(...skipping 29 matching lines...) Expand all
468 // When there is an error, we have to make the error the new 481 // When there is an error, we have to make the error the new
469 // result of the current listener. 482 // result of the current listener.
470 if (completeResult is! _Future) { 483 if (completeResult is! _Future) {
471 // This should be a rare case. 484 // This should be a rare case.
472 completeResult = new _Future(); 485 completeResult = new _Future();
473 completeResult._setError(error); 486 completeResult._setError(error);
474 } 487 }
475 _propagateToListeners(completeResult, listener); 488 _propagateToListeners(completeResult, listener);
476 }); 489 });
477 isPropagationAborted = true; 490 isPropagationAborted = true;
478 // We will reenter the listener's zone.
479 listener._zone.expectCallback();
480 } 491 }
481 } 492 }
482 } catch (e, s) { 493 } catch (e, s) {
483 // Set the exception as error. 494 // Set the exception as error.
484 listenerValueOrError = _asyncError(e, s); 495 listenerValueOrError = _asyncError(e, s);
485 listenerHasValue = false; 496 listenerHasValue = false;
486 } 497 }
487 if (listenerHasValue && listenerValueOrError is Future) {
488 // We are going to reenter the zone to finish what we started.
489 listener._zone.expectCallback();
490 }
491 }); 498 });
492 if (isPropagationAborted) return; 499 if (isPropagationAborted) return;
493 // If the listener's value is a future we need to chain it. 500 // If the listener's value is a future we need to chain it.
494 if (listenerHasValue && listenerValueOrError is Future) { 501 if (listenerHasValue && listenerValueOrError is Future) {
495 Future chainSource = listenerValueOrError; 502 Future chainSource = listenerValueOrError;
496 // Shortcut if the chain-source is already completed. Just continue the 503 // Shortcut if the chain-source is already completed. Just continue the
497 // loop. 504 // loop.
498 if (chainSource is _Future && (chainSource as _Future)._isComplete) { 505 if (chainSource is _Future && (chainSource as _Future)._isComplete) {
499 // propagate the value (simulating a tail call). 506 // propagate the value (simulating a tail call).
500 listener._isChained = true; 507 listener._isChained = true;
(...skipping 10 matching lines...) Expand all
511 listener._setValue(listenerValueOrError); 518 listener._setValue(listenerValueOrError);
512 } else { 519 } else {
513 listeners = listener._removeListeners(); 520 listeners = listener._removeListeners();
514 listener._setError(listenerValueOrError); 521 listener._setError(listenerValueOrError);
515 } 522 }
516 // Prepare for next round. 523 // Prepare for next round.
517 source = listener; 524 source = listener;
518 } 525 }
519 } 526 }
520 } 527 }
OLDNEW
« no previous file with comments | « sdk/lib/async/future.dart ('k') | sdk/lib/async/stream_controller.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698