runZoned<R> function

R runZoned <R>(R body(), { Map zoneValues, ZoneSpecification zoneSpecification, Function onError })

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 the onError handler is used both to handle asynchronous errors by overriding ZoneSpecification.handleUncaughtError in zoneSpecification, if any, and to handle errors thrown synchronously by the call to body.

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;
}