capture< T> method
If when
is true
, runs callback
in a Zone in which the current
stack chain is tracked and automatically associated with (most) errors.
If when
is false
, this does not track stack chains. Instead, it's
identical to runZoned, except that it wraps any errors in new
Chain.forTrace—which will only wrap the trace unless there's a different
Chain.capture active. This makes it easy for the caller to only capture
stack chains in debug mode or during development.
If onError
is passed, any error in the zone that would otherwise go
unhandled is passed to it, along with the Chain associated with that
error. Note that if callback
produces multiple unhandled errors,
onError
may be called more than once. If onError
isn't passed, the
parent Zone's unhandledErrorHandler
will be called with the error and
its chain.
If errorZone
is true
, the zone this creates will be an error zone,
even if onError
isn't passed. This means that any errors that would
cross the zone boundary are considered unhandled. If errorZone
is
false
, onError
must be null
.
If callback
returns a value, it will be returned by capture as well.
Implementation
static T capture<T>(T callback(),
{void onError(error, Chain chain),
bool when: true,
bool errorZone: true}) {
if (!errorZone && onError != null) {
throw new ArgumentError.value(
onError, "onError", "must be null if errorZone is false");
}
if (!when) {
var newOnError;
if (onError != null) {
newOnError = (error, stackTrace) {
onError(
error,
stackTrace == null
? new Chain.current()
: new Chain.forTrace(stackTrace));
};
}
return runZoned(callback, onError: newOnError);
}
var spec = new StackZoneSpecification(onError, errorZone: errorZone);
return runZoned(() {
try {
return callback();
} catch (error, stackTrace) {
// TODO(nweiz): Don't special-case this when issue 19566 is fixed.
Zone.current.handleUncaughtError(error, stackTrace);
return null;
}
},
zoneSpecification: spec.toSpec(),
zoneValues: {_specKey: spec, StackZoneSpecification.disableKey: false});
}