From e261360ac2720a3a7a6de57d053842feb31f5f1a Mon Sep 17 00:00:00 2001 From: Chris Calabro Date: Sat, 12 Apr 2014 07:46:59 -0700 Subject: [PATCH 1/3] docs look good --- lib/core/zone.dart | 91 +++++++++++++++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 26 deletions(-) diff --git a/lib/core/zone.dart b/lib/core/zone.dart index 25441bece..c7614cc3d 100644 --- a/lib/core/zone.dart +++ b/lib/core/zone.dart @@ -1,11 +1,18 @@ part of angular.core_internal; +/** + * Handles an [NgZone] onTurnDone event. + */ typedef void ZoneOnTurn(); + +/** + * Handles an [NgZone] onError event. + */ typedef void ZoneOnError(dynamic error, dynamic stacktrace, LongStackTrace longStacktrace); /** - * Contains the locations of runAsync calls across VM turns. + * Contains the locations of async calls across VM turns. */ class LongStackTrace { final String reason; @@ -26,25 +33,42 @@ class LongStackTrace { } /** - * A better zone API which implements onTurnDone. + * A [Zone] wrapper that lets you schedule tasks after its private microtask + * queue is exhausted but before the next "turn", i.e. event loop iteration. + * This lets you freely schedule microtasks that prepare data, and set an + * [onTurnDone] handler that will consume that data after it's ready but before + * the browser has a chance to re-render. + * The wrapper maintains an "inner" and "outer" [Zone] and a private queue of + * all the microtasks scheduled on the inner [Zone]. + * + * In a typical app, [ngDynamicApp] or [ngStaticApp] will create a singleton + * [NgZone] whose outer [Zone] is the root [Zone] and whose default [onTurnDone] + * runs the Angular digest. A component may want to inject this singleton if it + * needs to run code _outside_ the Angular digest. */ class NgZone { - final async.Zone _outerZone = async.Zone.current; - async.Zone _zone; + async.Zone _outerZone; + async.Zone _innerZone; + /** + * Associates with this + * - an "outer" [Zone], which is the one that created this. + * - an "inner" [Zone], which is a child of the outer [Zone]. + * Defaults [onError] to forward errors to the outer [Zone]. + * Defaults [onTurnDone] to a no-op. + */ NgZone() { - _zone = _outerZone.fork(specification: new async.ZoneSpecification( + _outerZone = async.Zone.current; + _innerZone = _outerZone.fork(specification: new async.ZoneSpecification( run: _onRun, runUnary: _onRunUnary, scheduleMicrotask: _onScheduleMicrotask, handleUncaughtError: _uncaughtError )); - // Prevent silently ignoring uncaught exceptions by forwarding such - // exceptions to the outer zone by default. - onError = (e, s, ls) => _outerZone.handleUncaughtError(e, s); + onError = _defaultOnError; + onTurnDone = _defaultOnTurnDone; } - List _asyncQueue = []; bool _errorThrownFromOnRun = false; @@ -107,21 +131,28 @@ class NgZone { int _runningInTurn = 0; /** - * A function called with any errors from the zone. + * Called with any errors from the inner zone. */ - var onError = (e, s, ls) => print('$e\n$s\n$ls'); + // We can't initialize onError to _defaultOnError here: dartbug 13519. + ZoneOnError onError; + // Prevent silently ignoring uncaught exceptions by forwarding such + // exceptions to the outer zone. + ZoneOnError _defaultOnError(dynamic e, dynamic s, LongStackTrace ls) => + _outerZone.handleUncaughtError(e, s); /** - * A function that is called at the end of each VM turn in which the - * in-zone code or any runAsync callbacks were run. + * Called at the end of each VM turn in which inner zone code runs. + * "At the end" means after the private microtask queue of the inner zone is + * exhausted but before the next VM turn. Notes + * - This won't wait for microtasks scheduled in zones other than the inner + * zone, e.g. those scheduled with [runOutsideAngular]. + * - [onTurnDone] runs repeatedly until it fails to schedule any more + * microtasks, so you usually don't want it to schedule any. For example, + * if its first line of code is `new Future.value()`, the turn will _never_ + * end. */ - var onTurnDone = () => null; // Type was ZoneOnTurn: dartbug 13519 - - /** - * A function that is called when uncaught errors are thrown inside the zone. - */ - // var onError = (dynamic e, dynamic s, LongStackTrace ls) => print('EXCEPTION: $e\n$s\n$ls'); - // Type was ZoneOnError: dartbug 13519 + ZoneOnTurn onTurnDone; + ZoneOnTurn _defaultOnTurnDone() => null; LongStackTrace _longStacktrace = null; @@ -140,15 +171,14 @@ class NgZone { } /** - * Runs the provided function in the zone. Any runAsync calls (e.g. futures) - * will also be run in this zone. - * - * Returns the return value of body. + * Runs [body] in the inner zone and returns whatever it returns. */ - dynamic run(body()) => _zone.run(body); + dynamic run(body()) => _innerZone.run(body); /** - * Allows one to escape the auto-digest mechanism of Angular. + * Runs [body] in the outer zone and returns whatever it returns. + * In a typical app where the inner zone is the Angular zone, this allows + * one to escape Angular's auto-digest mechanism. * * myFunction(NgZone zone, Element element) { * element.onClick.listen(() { @@ -163,10 +193,19 @@ class NgZone { */ dynamic runOutsideAngular(body()) => _outerZone.run(body); + /** + * Throws an [AssertionError] if no task is currently running in the inner + * zone. In a typical app where the inner zone is the Angular zone, this can + * be used to assert that the digest will indeed run at the end of the current + * turn. + */ void assertInTurn() { assert(_runningInTurn > 0 || _inFinishTurn); } + /** + * Same as [assertInTurn]. + */ void assertInZone() { assertInTurn(); } From 54ecb9882b362130137171953f3eda1ac53f6fc7 Mon Sep 17 00:00:00 2001 From: Chris Calabro Date: Sat, 12 Apr 2014 11:44:10 -0700 Subject: [PATCH 2/3] oops --- lib/core/zone.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/zone.dart b/lib/core/zone.dart index c7614cc3d..7f5fa4e72 100644 --- a/lib/core/zone.dart +++ b/lib/core/zone.dart @@ -137,7 +137,7 @@ class NgZone { ZoneOnError onError; // Prevent silently ignoring uncaught exceptions by forwarding such // exceptions to the outer zone. - ZoneOnError _defaultOnError(dynamic e, dynamic s, LongStackTrace ls) => + void _defaultOnError(dynamic e, dynamic s, LongStackTrace ls) => _outerZone.handleUncaughtError(e, s); /** @@ -152,7 +152,7 @@ class NgZone { * end. */ ZoneOnTurn onTurnDone; - ZoneOnTurn _defaultOnTurnDone() => null; + void _defaultOnTurnDone() => null; LongStackTrace _longStacktrace = null; From ccd6b694f107a45fd310413212ac15c3e0ba8f96 Mon Sep 17 00:00:00 2001 From: Chris Calabro Date: Mon, 14 Apr 2014 16:05:56 -0700 Subject: [PATCH 3/3] testing with dart2js seems to show dartbug 13519 is fixed --- lib/core/zone.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/core/zone.dart b/lib/core/zone.dart index 7f5fa4e72..3aa745fbe 100644 --- a/lib/core/zone.dart +++ b/lib/core/zone.dart @@ -133,7 +133,6 @@ class NgZone { /** * Called with any errors from the inner zone. */ - // We can't initialize onError to _defaultOnError here: dartbug 13519. ZoneOnError onError; // Prevent silently ignoring uncaught exceptions by forwarding such // exceptions to the outer zone.