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

Unified Diff: sdk/lib/async/zone.dart

Issue 17672002: Add runAsync interceptor. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove isolate import. Created 7 years, 6 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 side-by-side diff with in-line comments
Download patch
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) {

Powered by Google App Engine
This is Rietveld 408576698