runZoned<R> function
Runs body
in its own zone.
Creates a new zone using Zone.fork based on zoneSpecification
and
zoneValues
, then runs body
in that zone and returns the result.
If onError
is provided, it must have one of the types
void Function(Object)
void Function(Object, StackTrace)
and theonError
handler is used both to handle asynchronous errors by overriding ZoneSpecification.handleUncaughtError inzoneSpecification
, if any, and to handle errors thrown synchronously by the call tobody
.
If an error occurs synchronously in body
,
then throwing in the onError
handler
makes the call to runZone
throw that error,
and otherwise the call to runZoned
returns null
.
If the zone specification has a handleUncaughtError
value or the onError
parameter is provided, the zone becomes an error-zone.
Errors will never cross error-zone boundaries by themselves. Errors that try to cross error-zone boundaries are considered uncaught in their originating error zone.
var future = new Future.value(499);
runZoned(() {
var future2 = future.then((_) { throw "error in first error-zone"; });
runZoned(() {
var future3 = future2.catchError((e) { print("Never reached!"); });
}, onError: (e) { print("unused error handler"); });
}, onError: (e) { print("catches error of first error-zone."); });
Example:
runZoned(() {
new Future(() { throw "asynchronous error"; });
}, onError: print); // Will print "asynchronous error".
It is possible to manually pass an error from one error zone to another
by re-throwing it in the new zone. If onError
throws, that error will
occur in the original zone where runZoned was called.
Implementation
R runZoned<R>(R body(),
{Map zoneValues, ZoneSpecification zoneSpecification, Function onError}) {
if (onError == null) {
return _runZoned<R>(body, zoneValues, zoneSpecification);
}
void Function(Object) unaryOnError;
void Function(Object, StackTrace) binaryOnError;
if (onError is void Function(Object, StackTrace)) {
binaryOnError = onError;
} else if (onError is void Function(Object)) {
unaryOnError = onError;
} else {
throw new ArgumentError("onError callback must take either an Object "
"(the error), or both an Object (the error) and a StackTrace.");
}
HandleUncaughtErrorHandler errorHandler = (Zone self, ZoneDelegate parent,
Zone zone, error, StackTrace stackTrace) {
try {
if (binaryOnError != null) {
self.parent.runBinary(binaryOnError, error, stackTrace);
} else {
assert(unaryOnError != null);
self.parent.runUnary(unaryOnError, error);
}
} catch (e, s) {
if (identical(e, error)) {
parent.handleUncaughtError(zone, error, stackTrace);
} else {
parent.handleUncaughtError(zone, e, s);
}
}
};
if (zoneSpecification == null) {
zoneSpecification =
new ZoneSpecification(handleUncaughtError: errorHandler);
} else {
zoneSpecification = new ZoneSpecification.from(zoneSpecification,
handleUncaughtError: errorHandler);
}
try {
return _runZoned<R>(body, zoneValues, zoneSpecification);
} catch (e, stackTrace) {
if (binaryOnError != null) {
binaryOnError(e, stackTrace);
} else {
assert(unaryOnError != null);
unaryOnError(e);
}
}
return null;
}