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

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

Issue 2082553003: More documentation for zones. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: A few small improvements. Created 4 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/async/zone.dart
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index 32fb627b39742eb03c7a049ec0fdd20b298eb896..39ba2e0645ccd412af6a46e3027f9f6d7e97ea0b 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -277,14 +277,26 @@ class _ZoneSpecification implements ZoneSpecification {
}
/**
- * This class wraps zones for delegation.
+ * An adapted view of the parent zone.
*
- * When forwarding to parent zones one can't just invoke the parent zone's
- * exposed functions (like [Zone.run]), but one needs to provide more
- * information (like the zone the `run` was initiated). Zone callbacks thus
- * receive more information including this [ZoneDelegate] class. When delegating
- * to the parent zone one should go through the given instance instead of
- * directly invoking the parent zone.
+ * This class allows the implementation of a zone method to invoke methods on
+ * the parent zone while retaining knowledge of the originating zone.
+ *
+ * Custom zones (created through [Zone.fork] or [runZoned]) can provide
+ * implementations of most methods of zones. This is similar to overriding
+ * methods on [Zone], except that this mechanism doesn't require subclassing.
+ *
+ * A custom zone function (provided through a [ZoneSpecification]) typically
+ * records or wraps its parameters and then delegates the operation to its
+ * parent zone using the provided [ZoneDelegate].
+ *
+ * While zones have access to their parent zone (through [Zone.parent]) it is
+ * recommended to call the methods on the provided parent delegate for two
+ * reasons:
+ * 1. the delegate methods take an additional `zone` argument which is the
+ * zone the action has been initiated in.
+ * 2. delegate calls are more efficient, since the implementation knows how
+ * to skip zones that would just delegate to their parents.
*/
abstract class ZoneDelegate {
/*=R*/ handleUncaughtError/*<R>*/(
@@ -318,117 +330,268 @@ abstract class ZoneDelegate {
}
/**
- * A Zone represents the asynchronous version of a dynamic extent. Asynchronous
- * callbacks are executed in the zone they have been queued in. For example,
- * the callback of a `future.then` is executed in the same zone as the one where
- * the `then` was invoked.
+ * A zone represents an environment that remains stable across asynchronous
+ * calls.
+ *
+ * Asynchronous callbacks are executed in the zone they have been queued in. For
+ * example, the callback of a `future.then` is executed in the same zone as the
+ * one where the `then` was invoked.
Lasse Reichstein Nielsen 2016/07/01 11:25:01 Consider moving this paragraph somewhere after "Co
floitsch 2016/07/02 03:11:20 Done. Removed.
+ *
+ * Code is always executed in the context of a zone, available as
+ * [Zone.current]. The initial `main` function runs in the context of the
+ * default zone ([Zone.ROOT]). Code can be run in a different zone using either
+ * [runZoned], to create a new zone, or [Zone.run] to run code in the context of
+ * an existing zone likely created using [Zone.fork].
+ *
+ * Developers can create a new zone that overrides some of the functionality of
+ * an existing zone. For example, custom zones can replace of modify the
+ * behavior of `print`, timers, microtasks or how uncaught errors are handled.
+ *
+ * The [Zone] class is not subclassable, but users can provide custom zones by
+ * forking an existing zone (usually [Zone.current]) with a [ZoneSpecification].
+ * This is similar to creating a new class that extends the base `Zone` class
+ * and that overrides some methods, except without actually creating a new
+ * class. Instead the overriding methods are provided as functions that
+ * explicitly take the equivalent of their own class, the "super" class and the
+ * `this` object as parameters.
+ *
+ * Asynchronous callbacks always run in the context of the zone where they were
+ * scheduled. This is implemented using two steps:
Lasse Reichstein Nielsen 2016/07/01 11:25:01 Is this repeating paragraph 2 above? (if so, maybe
floitsch 2016/07/02 03:11:19 Done.
+ * 1. the callback is first registered using one of [registerCallback],
+ * [registerUnaryCallback], or [registerBinaryCallback]. This allows the zone
+ * to record that a callback exists and potentially modify it (by returning a
+ * different callback). The code doing the registration (e.g., `Future.then`)
+ * also remembers the current zone so that it can later run the callback in
+ * that zone.
+ * 2. At a later point the registered callback is run in the remembered zone.
+ *
+ * This is all handled internally by the platform code and most users don't need
+ * to worry about it. However, developers of new asynchronous operations,
+ * provided by the underlying system or through native extensions, must follow
+ * the protocol to be zone compatible.
+ *
+ * For convenience, zones provide [bindCallback] (and the corresponding
+ * [bindUnaryCallback] or [bindBinaryCallback]) to make it easier to respect the
+ * zone contract: these functions first invoke the corresponding `register`
+ * functions and then wrap the returned function so that it runs in the current
+ * zone when it is later asynchronously invoked.
*/
abstract class Zone {
// Private constructor so that it is not possible instantiate a Zone class.
Zone._();
- /** The root zone that is implicitly created. */
+ /**
+ * The root zone.
+ *
+ * All isolate entry functions (`main` or spawned functions) start running in
+ * the root zone. Without any custom zone the whole program always runs in the
Lasse Reichstein Nielsen 2016/07/01 11:25:01 Without any custom zone .. -> If no custom zone i
floitsch 2016/07/02 03:11:20 Done.
+ * root zone and [Zone.current] is always identical to [Zone.ROOT].
+ *
+ * The root zone implements the default behavior of all zone operations.
+ * Many methods, like [registerCallback] do the bare minimum, others, like
Lasse Reichstein Nielsen 2016/07/01 11:25:01 ... do the bare minimum, and are only provided as
floitsch 2016/07/02 03:11:20 Done.
+ * [scheduleMicrotask] interact with the underlying system to implement the
Lasse Reichstein Nielsen 2016/07/01 11:25:01 comma before interact.
floitsch 2016/07/02 03:11:19 Done.
+ * desired behavior.
+ */
static const Zone ROOT = _ROOT_ZONE;
/** The currently running zone. */
static Zone _current = _ROOT_ZONE;
+ /** The zone that is currently active. */
static Zone get current => _current;
+ /**
+ * Handles uncaught asynchronous errors.
+ *
+ * There are two kind of asynchronous errors that are handled by this
+ * function:
+ * 1. uncaught errors that were thrown in asynchronous callbacks. For example,
Lasse Reichstein Nielsen 2016/07/01 11:25:01 Start with capital letter. I'd prefer a comma inst
floitsch 2016/07/02 03:11:19 Done.
+ * a `throw` in [Timer.run].
Lasse Reichstein Nielsen 2016/07/01 11:25:02 ... a throw in the function passed to [Timer.run].
floitsch 2016/07/02 03:11:19 Done.
+ * 2. asynchronous errors that are pushed down [Future] and [Stream] chains
Lasse Reichstein Nielsen 2016/07/01 11:25:01 Start with capital letter again. maybe: down -> th
floitsch 2016/07/02 03:11:20 Done.
+ * but for which no child registered an error handled.
Lasse Reichstein Nielsen 2016/07/01 11:25:01 Comma before but (it's optional, but I would prefe
floitsch 2016/07/02 03:11:19 Done.
+ * Most asynchronous classes, like [Future] or [Stream] push errors to their
+ * listeners. Errors are propagated this way until either a listener handles
+ * the error (for example with [Future.catchError]), or no listener is
+ * available anymore. In the latter case, futures and streams invoke the
+ * zone's [handleUncaughtError].
+ *
+ * By default, when handled by the root zone, uncaught asynchronous errors are
+ * treated like synchronous uncaught exceptions.
Lasse Reichstein Nielsen 2016/07/01 11:25:01 I'd say "uncaught synchronous exceptions". I just
floitsch 2016/07/02 03:11:19 Done.
+ */
/*=R*/ handleUncaughtError/*<R>*/(error, StackTrace stackTrace);
/**
* Returns the parent zone.
Lasse Reichstein Nielsen 2016/07/01 11:25:01 Describe a getter like a property, not a method. I
floitsch 2016/07/02 03:11:20 Done.
*
* Returns `null` if `this` is the [ROOT] zone.
Lasse Reichstein Nielsen 2016/07/01 11:25:01 -> Is `null` if ...
floitsch 2016/07/02 03:11:20 Done.
+ *
+ * Zones are created by [fork] on an existing zone, or by [runZoned] which
+ * forks the [current] zone. The new zone's parent zone is the zone it was
+ * forked from.
*/
Zone get parent;
/**
* The error zone is the one that is responsible for dealing with uncaught
* errors.
- * Errors are not allowed to cross between zones with different error-zones.
*
- * This is the closest parent or ancestor zone of this zone that has a custom
+ * This is the closest parent zone of this zone that provides a
* [handleUncaughtError] method.
+ *
+ * Asynchronous errors never cross zone boundaries between zones with
+ * different error handlers.
+ *
+ * Example:
+ * ```
+ * import 'dart:async';
+ *
+ * main() {
+ * var future;
+ * runZoned(() {
+ * // The asynchronous error is caught by the custom zone which prints
+ * // 'asynchronous error'.
+ * future = new Future.error("asynchronous error");
+ * }, onError: (e) { print(e); }); // Creates a zone with an error handler.
+ * // The following `catchError` handler is never invoked, because the
+ * // custom zone created by the call to `runZoned` provides an
+ * // error handler.
+ * future.catchError((e) { throw "is never reached"; });
+ * }
+ * ```
+ *
+ * Note that errors can not enter a child zone with a different error handler
Lasse Reichstein Nielsen 2016/07/01 11:25:01 can not -> cannot (or can't).
floitsch 2016/07/02 03:11:20 Done.
+ * either:
+ * ```
+ * import 'dart:async';
+ *
+ * main() {
+ * runZoned(() {
+ * // The following asynchronous error is *not* caught by the `catchError`
+ * // in the nested zone, since errors are not to cross zone boundaries
+ * // with different error handlers.
+ * // Instead the error is handled by the current error handler,
+ * // printing "Caught by outer zone: asynchronous error".
+ * var future = new Future.error("asynchronous error");
+ * runZoned(() {
+ * future.catchError((e) { throw "is never reached"; });
+ * }, onError: (e) { throw "is never reached"; });
+ * }, onError: (e) { print("Caught by outer zone: $e"); });
+ * }
+ * ```
*/
Zone get errorZone;
/**
* Returns true if `this` and [otherZone] are in the same error zone.
*
- * Two zones are in the same error zone if they inherit their
- * [handleUncaughtError] callback from the same [errorZone].
+ * Two zones are in the same error zone if they have the same [errorZone].
*/
bool inSameErrorZone(Zone otherZone);
/**
* Creates a new zone as a child of `this`.
*
- * The new zone will have behavior like the current zone, except where
- * overridden by functions in [specification].
+ * The new zone uses the closures in the given [specification] to override
+ * the current's zone behavior. All specification entries that are `null`
+ * inherit the behavior from the parent zone (`this`).
*
- * The new zone will have the same stored values (accessed through
- * `operator []`) as this zone, but updated with the keys and values
- * in [zoneValues]. If a key is in both this zone's values and in
- * `zoneValues`, the new zone will use the value from `zoneValues``.
+ * The new zone inherits the stored values (accessed through `operator []`)
Lasse Reichstein Nielsen 2016/07/04 14:14:19 [operator []] (if you can write that in DartDoc
floitsch 2016/07/05 15:39:57 Dartdoc doesn't link it, but at least doesn't "bre
+ * of this zone and updates them with values from [zoneValues], which either
+ * adds new values or overrides existing ones.
+ *
+ * Note that the fork operation is interceptible. A zone can thus change
+ * the zone specification (or zone values), giving the forking zone full
+ * control over the child zone.
*/
- Zone fork({ ZoneSpecification specification,
- Map zoneValues });
+ Zone fork({ZoneSpecification specification,
+ Map zoneValues});
/**
- * Executes the given function [f] in this zone.
+ * Executes [action] in this zone.
+ *
+ * By default (as implemented in the [ROOT] zone), runs [action]
+ * with [current] set to this zone.
+ *
+ * If [action] throws, the synchronous exception is not caught by the zone's
+ * error handler. Use [runGuarded] to achieve that.
+ *
+ * Since the root zone is the only zone that can modify the value of
+ * [current], custom zones intercepting run should always delegate to their
+ * parent zone. They may take actions before and after the call.
*/
- /*=R*/ run/*<R>*/(/*=R*/ f());
+ /*=R*/ run/*<R>*/(/*=R*/ action());
/**
- * Executes the given callback [f] with argument [arg] in this zone.
+ * Executes the given [action] with [argument] in this zone.
+ *
+ * As [run] except that [action] is called with one [argument] instead of
+ * none.
*/
- /*=R*/ runUnary/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg);
+ /*=R*/ runUnary/*<R, T>*/(/*=R*/ action(/*=T*/ argument), /*=T*/ argument);
/**
- * Executes the given callback [f] with argument [arg1] and [arg2] in this
+ * Executes the given [action] with [argument1] and [argument2] in this
* zone.
+ *
+ * As [run] except that [action] is called with two arguments instead of none.
*/
/*=R*/ runBinary/*<R, T1, T2>*/(
- /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2);
+ /*=R*/ action(/*=T1*/ argument1, /*=T2*/ argument2), /*=T1*/ argument1,
+ /*=T2*/ argument2);
/**
- * Executes the given function [f] in this zone.
+ * Executes the given [action] in this zone and catches synchronous
+ * errors.
+ *
+ * This function is equivalent to:
+ * ```
+ * try {
+ * return this.run(action);
+ * } catch (e, s) {
+ * return this.handleUncaughtError(e, s);
+ * }
+ * ```
*
- * Same as [run] but catches uncaught errors and gives them to
- * [handleUncaughtError].
+ * See [run].
*/
- /*=R*/ runGuarded/*<R>*/(/*=R*/ f());
+ /*=R*/ runGuarded/*<R>*/(/*=R*/ action());
/**
- * Executes the given callback [f] in this zone.
+ * Executes the given [action] with [argument] in this zone and
+ * catches synchronous errors.
*
- * Same as [runUnary] but catches uncaught errors and gives them to
- * [handleUncaughtError].
+ * See [runGuarded].
*/
- /*=R*/ runUnaryGuarded/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg);
+ /*=R*/ runUnaryGuarded/*<R, T>*/(/*=R*/ action(/*=T*/ argument),
+ /*=T*/ argument);
/**
- * Executes the given callback [f] in this zone.
+ * Executes the given [action] with [argument1] and [argument2] in this
+ * zone and catches synchronous errors.
*
- * Same as [runBinary] but catches uncaught errors and gives them to
- * [handleUncaughtError].
+ * See [runGuarded].
*/
/*=R*/ runBinaryGuarded/*<R, T1, T2>*/(
- /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2);
+ /*=R*/ action(/*=T1*/ argument1, /*=T2*/ argument2), /*=T1*/ argument1,
+ /*=T2*/ argument2);
/**
* Registers the given callback in this zone.
*
- * It is good practice to register asynchronous or delayed callbacks before
- * invoking [run]. This gives the zone a chance to wrap the callback and
- * to store information with the callback. For example, a zone may decide
+ * When implementing an asynchronous primitive that uses callbacks, the
+ * callback must be registered using [registerCallback] at the point where the
+ * user provides the callback. This allows zones to record other information
+ * that they need at the same time, perhaps even wrapping the callback, so
+ * that the callback is prepared when it is later run in the same zones
+ * (using [run]). For example, a zone may decide
* to store the stack trace (at the time of the registration) with the
* callback.
*
- * Returns a potentially new callback that should be used in place of the
- * given [callback].
+ * Returns the callback that should be used in place of the provided
+ * [callback]. Frequently zones simply return the original callback.
+ *
+ * Custom zones may intercept this operation. The default implementation in
+ * [Zone.ROOT] returns the original callback unchanged.
*/
ZoneCallback/*<R>*/ registerCallback/*<R>*/(/*=R*/ callback());
@@ -451,86 +614,146 @@ abstract class Zone {
/**
* Equivalent to:
*
- * ZoneCallback registered = registerCallback(f);
+ * ZoneCallback registered = this.registerCallback(action);
* if (runGuarded) return () => this.runGuarded(registered);
* return () => this.run(registered);
*
*/
ZoneCallback/*<R>*/ bindCallback/*<R>*/(
- /*=R*/ f(), { bool runGuarded: true });
+ /*=R*/ action(), { bool runGuarded: true });
/**
* Equivalent to:
*
- * ZoneCallback registered = registerUnaryCallback(f);
+ * ZoneCallback registered = this.registerUnaryCallback(action);
* if (runGuarded) return (arg) => this.runUnaryGuarded(registered, arg);
* return (arg) => thin.runUnary(registered, arg);
*/
ZoneUnaryCallback/*<R, T>*/ bindUnaryCallback/*<R, T>*/(
- /*=R*/ f(/*=T*/ arg), { bool runGuarded: true });
+ /*=R*/ action(/*=T*/ argument), { bool runGuarded: true });
/**
* Equivalent to:
*
- * ZoneCallback registered = registerBinaryCallback(f);
+ * ZoneCallback registered = registerBinaryCallback(action);
* if (runGuarded) {
* return (arg1, arg2) => this.runBinaryGuarded(registered, arg);
* }
* return (arg1, arg2) => thin.runBinary(registered, arg1, arg2);
*/
ZoneBinaryCallback/*<R, T1, T2>*/ bindBinaryCallback/*<R, T1, T2>*/(
- /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), { bool runGuarded: true });
+ /*=R*/ action(/*=T1*/ argument1, /*=T2*/ argument2),
+ { bool runGuarded: true });
/**
- * Intercepts errors when added programmatically to a `Future` or `Stream`.
+ * Intercepts errors when added programatically to a `Future` or `Stream`.
+ *
+ * When calling [Completer.completeError], [Stream.addError],
+ * or for some [Future] constructors the current zone is allowed to intercept
Lasse Reichstein Nielsen 2016/07/01 11:25:01 remove "for". Consider a comma before "the current
floitsch 2016/07/02 03:11:19 Done.
+ * and replace the error.
+ *
+ * Future constructors invoke this function when the error is received
+ * directly, for example with [Future.error], or when the error is caught
+ * synchronously, for example with [Future.sync].
*
- * When caling [Completer.completeError], [Stream.addError],
- * or [Future] constructors that take an error or a callback that may throw,
- * the current zone is allowed to intercept and replace the error.
+ * There is no guarantee that an error is only sent through [errorCallback]
+ * once. Libraries that use intermediate controllers or completers might
+ * end up invoking [errorCallback] multiple times.
*
- * When other libraries use intermediate controllers or completers, such
- * calls may contain errors that have already been processed.
+ * Returns `null` if no replacement is desired. Otherwise returns an instance
+ * of [AsyncError] holding the new pair of error and stack trace.
*
- * Return `null` if no replacement is desired.
- * The original error is used unchanged in that case.
- * Otherwise return an instance of [AsyncError] holding
- * the new pair of error and stack trace.
- * If the [AsyncError.error] is `null`, it is replaced by a [NullThrownError].
+ * Although not recommended, the returned instance may have its `error` member
+ * ([AsyncError.error]) be equal to `null` in which case the error should be
+ * replaced by a [NullThrownError].
+ *
+ * Custom zones may intercept this operation.
+ *
+ * Implementations of a new asynchronous primitive that converts synchronous
+ * errors to asynchronous errors rarely need to invoke [errorCallback], since
+ * errors are usually reported through future completers or stream
+ * controllers.
*/
AsyncError errorCallback(Object error, StackTrace stackTrace);
/**
- * Runs [f] asynchronously in this zone.
+ * Runs [action] asynchronously in this zone.
+ *
+ * The global `scheduleMicrotask` delegates to the current zone's
+ * [scheduleMicrotask]. The root zone's implementation interacts with the
+ * underlying system to schedule the given callback as a microtask.
+ *
+ * Custom zones may intercept this operation (for example to wrap the given
+ * callback [action]).
*/
- void scheduleMicrotask(void f());
+ void scheduleMicrotask(void action());
/**
- * Creates a task, given a [create] function and a [specification].
+ * Creates a task in the current zone.
*
- * The [create] function is invoked with the [specification] as argument. It
- * returns a task object which is used for all future interactions with the
- * zone.
+ * A task represents an asynchronous operation or process that reports back
+ * through the event loop.
*
- * Custom zones may replace the [specification] with a different one, thus
- * modifying the task parameters.
+ * This function allows the zone to intercept the initialization of the
+ * task while the [runTask] function is invoked when the task reports back.
+ *
+ * By default, in the root zone, the [create] function is invoked with the
+ * [specification] as argument. It returns a task object which is used for all
+ * future interactions between the zone and the task. The object is
+ * a unique instance representing the task. It is generally returned to
+ * whoever initiated the task.
+ * For example, the HTML library uses the returned [StreamSubscription] as
+ * task object when users register an event listener.
*
- * Tasks are created when the program is starting an operation that returns
- * through the event loop. For example, a timer or an http request both
+ * Tasks are created when the program starts an operation that reports back
+ * through the event loop. For example, a timer or an HTTP request both
* return through the event loop and are therefore tasks.
*
* If the [create] function is not invoked (because a custom zone has
* replaced or intercepted it), then the operation is *not* started. This
- * means that a custom zone can intercept tasks, like http requests.
+ * means that a custom zone can intercept tasks, like HTTP requests.
+ *
+ * A task goes through the following steps:
+ * - a user invokes a library function that should eventually return through
+ * the event loop.
+ * - the library function creates a [TaskSpecification] that contains the
+ * necessary information to start the operation, and invokes
+ * `Zone.current.createTask` with the specification and a [create] closure.
+ * The closure, when invoked, uses the specification to start the operation
+ * (usually by interacting with the underlying system, or as a native
+ * extension), and returns a task object that identifies the running task.
+ * - custom zones handle the request and (unless completely intercepted and
+ * aborted), end up calling the root zone's [createTask] which runs the
+ * provided `create` closure, which may have been replaced at this point.
+ * - later, the asynchronous operation returns through the event loop.
+ * It invokes [Zone.runTask] on the zone in which the task should run
+ * (and which was originally passed to the `create` function by
+ * `createTask`). The [runTask] function receives the
+ * task object, a `run` function and an argument. As before, custom zones
+ * may intercept this call. Eventually (unless aborted), the `run` function
+ * is invoked. This last step may happen multiple times for tasks that are
+ * not oneshot tasks (see [ZoneSpecification.isOneShot]).
+ *
+ * Custom zones may replace the [specification] with a different one, thus
+ * modifying the task parameters. An operation that wishes to be an
+ * interceptable task must publicly specify the types that intercepting code
+ * sees:
+ * - The specification type (extending [TaskSpecification]) which holds the
+ * information available when intercepting the `createTask` call.
+ * - The task object type, returned by `createTask` and [create]. This object
+ * may simply be typed as [Object].
+ * - The argument type, if [runTask] takes a meaningful argument.
*
* *Experimental*. Might disappear without notice.
*/
- Object/*=T*/ createTask/*<T, S>*/(
- TaskCreate/*<T, S>*/ create, TaskSpecification/*=S*/ specification);
+ Object/*=T*/ createTask/*<T, S extends TaskSpecification>*/(
+ /*=T*/ create(S specification, Zone zone),
+ TaskSpecification/*=S*/ specification);
/**
* Runs a task callback.
*
- * This function is invoked, when an operation, started through [createTask],
+ * This function is invoked when an operation, started through [createTask],
* returns to Dart code.
*
* Generally, tasks schedule Dart code in the global event loop. As such,
@@ -538,14 +761,17 @@ abstract class Zone {
*
* The [task] object must be the same as the one created with [createTask].
*
- * It is good practice, if task operations provide a meaningful [arg], so
+ * It is good practice, if task operations provide a meaningful [argument], so
* that custom zones can deal with it. They might want to log it, or
* replace it.
*
+ * See [createTask].
+ *
* *Experimental*. Might disappear without notice.
*/
void runTask/*<T, A>*/(
- TaskRun/*<T, A>*/ run, Object/*=T*/ task, Object/*=A*/ arg);
+ /*=T*/ run(/*=T*/ task, /*=A*/ argument), Object/*=T*/ task,
+ Object/*=A*/ argument);
/**
* Creates a Timer where the callback is executed in this zone.
@@ -561,6 +787,24 @@ abstract class Zone {
/**
* Prints the given [line].
+ *
+ * The global `print` function delegates to the current zone's [print]
+ * function which makes it possible to intercept printing.
+ *
+ * Example:
+ * ```
+ * import 'dart:async';
+ *
+ * main() {
+ * runZoned(() {
+ * // Ends up printing: "Intercepted: in zone".
+ * print("in zone");
+ * }, zoneSpecification: new ZoneSpecification(
+ * print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
+ * parent.print(zone, "Intercepted: $line");
+ * }));
+ * }
+ * ```
*/
void print(String line);
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698