Chromium Code Reviews| Index: sdk/lib/async/zone.dart |
| diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart |
| index 1379128838ea517fcb325595f94296b6197cef08..474bdc99958bf514d9dc8b33cc6571f5f5dda046 100644 |
| --- a/sdk/lib/async/zone.dart |
| +++ b/sdk/lib/async/zone.dart |
| @@ -38,8 +38,8 @@ abstract class _Zone { |
| * Tells the zone that it needs to wait for one more callback before it is |
| * done. |
| * |
| - * Use [executeCallback] or [cancelCallbackExpectation] when the callback is executed |
| - * (or canceled). |
| + * Use [executeCallback] or [cancelCallbackExpectation] when the callback is |
| + * executed (or canceled). |
| */ |
| void expectCallback(); |
| @@ -80,9 +80,23 @@ abstract class _Zone { |
| void executePeriodicCallbackGuarded(void fun()); |
| /** |
| - * Runs [fun] asynchronously in this zone. |
| + * Execute [fun] in `this` zone. |
|
Lasse Reichstein Nielsen
2013/06/26 09:24:29
"fun" is untraditional naming: either "action" or
floitsch
2013/06/26 12:22:56
Done.
|
| + * |
| + * The behavior of this method should be the same as |
| + * [executePeriodicCallback] except that it can have a return value. |
| + */ |
| + runFromChildZone(fun()); |
| + |
| + /** |
| + * Same as [runFromChildZone] but catches uncaught errors and gives them to |
| + * [handleUncaughtError]. |
| + */ |
| + runFromChildZoneGuarded(fun()); |
| + |
| + /** |
| + * Runs [fun] asynchronously in [zone]. |
| */ |
| - void runAsync(void fun()); |
| + void runAsync(void fun(), _Zone zone); |
| /** |
| * Creates a Timer where the callback is executed in this zone. |
| @@ -220,6 +234,9 @@ class _ZoneBase implements _Zone { |
| this._runGuarded(fun); |
| } |
| + runFromChildZone(fun()) => this._runUnguarded(fun); |
| + runFromChildZoneGuarded(fun()) => this._runGuarded(fun); |
| + |
| _runInZone(fun(), bool handleUncaught) { |
| if (identical(_Zone._current, this) |
| && !handleUncaught |
| @@ -271,23 +288,23 @@ class _ZoneBase implements _Zone { |
| return _runInZone(fun, false); |
| } |
| - runAsync(void fun()) { |
| - _openCallbacks++; |
| - _scheduleAsyncCallback(() { |
| - _openCallbacks--; |
| - _runGuarded(fun); |
| - }); |
| - } |
| + runAsync(void fun(), _Zone zone) => _parentZone.runAsync(fun, zone); |
| + // TODO(floitsch): the zone should just forward to the parent zone. The |
| + // default zone should then create the _ZoneTimer. |
| Timer createTimer(Duration duration, void callback()) { |
| return new _ZoneTimer(this, duration, callback); |
| } |
| + // TODO(floitsch): the zone should just forward to the parent zone. The |
| + // default zone should then create the _ZoneTimer. |
| Timer createPeriodicTimer(Duration duration, void callback(Timer timer)) { |
| return new _PeriodicZoneTimer(this, duration, callback); |
| } |
| void _addChild(_Zone child) { |
| + // TODO(floitsch): the zone should just increment a counter, but not keep |
| + // a reference to the child. |
| _children.add(child); |
| } |
| @@ -332,6 +349,18 @@ class _DefaultZone extends _ZoneBase { |
| throw error; |
| }); |
| } |
| + |
| + void runAsync(void fun(), _Zone zone) { |
| + if (identical(this, zone)) { |
| + // No need to go through the zone when it's the default zone anyways. |
| + _scheduleAsyncCallback(fun); |
| + return; |
| + } |
| + zone.expectCallback(); |
| + _scheduleAsyncCallback(() { |
| + zone.executeCallbackGuarded(fun); |
| + }); |
| + } |
| } |
| typedef void _CompletionCallback(); |
| @@ -370,7 +399,7 @@ class _CatchErrorsZone extends _WaitForCompletionZone { |
| final _HandleErrorCallback _handleError; |
| _CatchErrorsZone(_Zone parentZone, this._handleError, void onDone()) |
| - : super(parentZone, onDone); |
| + : super(parentZone, onDone); |
| _Zone get _errorZone => this; |
| @@ -394,7 +423,23 @@ class _CatchErrorsZone extends _WaitForCompletionZone { |
| return this._runGuarded(fun); |
| } |
| - String toString() => "WithErrors ${super.toString()}"; |
| + String toString() => "CatchErrors ${super.toString()}"; |
| +} |
| + |
| +typedef void _RunAsyncInterceptor(void callback()); |
| + |
| +class _RunAsyncZone extends _ZoneBase { |
| + final _RunAsyncInterceptor _runAsyncInterceptor; |
| + |
| + _RunAsyncZone(_Zone parentZone, this._runAsyncInterceptor) |
| + : super(parentZone); |
| + |
| + void runAsync(void callback(), _Zone zone) { |
| + zone.expectCallback(); |
| + _parentZone.runFromChildZone(() { |
| + _runAsyncInterceptor(() => zone.executeCallbackGuarded(callback)); |
| + }); |
| + } |
| } |
| typedef void _TimerCallback(); |
| @@ -463,6 +508,12 @@ class _PeriodicZoneTimer implements Timer { |
| * [onDone] (if non-null) is invoked when the zone has no more outstanding |
|
Lasse Reichstein Nielsen
2013/06/26 09:24:29
[onDone] -> The [onDone] callback
(avoid initial l
floitsch
2013/06/26 12:22:56
Done.
|
| * callbacks. |
| * |
| + * [onRunAsync] (if non-null) is invoked when the [body] executes [runAsync]. |
|
Lasse Reichstein Nielsen
2013/06/26 09:24:29
Ditto.
floitsch
2013/06/26 12:22:56
Done.
|
| + * The handler is invoked in the outer zone and can therefore execute |
| + * [runAsync] without invoking itself. The given callback must be executed |
| + * eventually. Otherwise the nested zone will not complete. It must be |
| + * executed only once. |
| + * |
| * Examples: |
| * |
| * runZonedExperimental(() { |
| @@ -489,8 +540,27 @@ class _PeriodicZoneTimer implements Timer { |
| * }, onError: (e) { print("unused error handler"); }); |
| * }, onError: (e) { print("catches error of first error-zone."); }); |
| * |
| + * The following example prints the stack trace whenever a callback is |
| + * registered using [runAsync] (which is also used by [Completer]s and |
| + * [StreamController]s. |
| + * |
| + * printStackTrace() { try { throw 0; } catch(e, s) { print(s); } } |
| + * runZonedExperimental(body, onRunAsync: (callback) { |
| + * printStackTrace(); |
| + * runAsync(callback); |
| + * }); |
| */ |
| -runZonedExperimental(body(), { void onError(error), void onDone() }) { |
| +runZonedExperimental(body(), |
| + { void onRunAsync(void callback()), |
| + void onError(error), |
| + void onDone() }) { |
| + if (onRunAsync != null) { |
| + _RunAsyncZone zone = new _RunAsyncZone(_Zone._current, onRunAsync); |
| + return zone._runUnguarded(() { |
| + return runZonedExperimental(body, onError: onError, onDone: onDone); |
| + }); |
| + } |
| + |
| // TODO(floitsch): we probably still want to install a new Zone. |
| if (onError == null && onDone == null) return body(); |
| if (onError == null) { |