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