-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add an API wrapping runZonedGuarded that surfaces the first error #263
Comments
We could change I think that'll be mostly non-breaking for reasonable uses. We could also add a flag that makes it replace a successful completion with an error if there has been any unhandled async error before completion. I'm less convinced by that, because it seems at odds with how async operations behave.
Seems more consistent to not use an existing error, but instead replace the successful completion with a |
We should go through the breaking change process and double check this assumption. I think the typical patterns to work around current behavior should be OK since they typically check I can imagine that some implementations may double-log an error if it starts to also surface as an error future in the calling zone. Edit: If we only surface this error through the returned Future and stop calling the
I think current workarounds are more likely to surface the error immediately and not wait for the successful completion. |
I checked my assumptions, and it won't work. Turns out the While we can keep doing that, and make an async error future smuggle the error out (maybe), it's not consistent. But it would also change the behavior of never needing to handle errors from a returned future. I'm not very keen on eagerly completing the returned future with an unhandled async error. For two reasons.
I almost had a way of smuggling an error past the zone, by doing class Banana implements Future<bool> { Future<bool> _banana; ... }
...
Banana createBanana() => ...
var b = runZoneGuarded(createBanana, (e, s) => ...); Here the type parameter, and type of of We might be able to do the hack if the type parameter is So, all in all, |
A possible alternative could be: import "dart:async";
/// Runs [action] in a new [Zone] where [onError] handles uncaught errors.
///
/// Returns the result of [action]. If that result is a [Future], it is
/// copied into a future belonging to the surrounding zone, so that
/// an error can be handled.
Future<R> catchUnhandledAsyncErrors<R>(
FutureOr<R> Function() action, {
required void Function(Object, StackTrace) onError,
ZoneSpecification? zoneSpecification,
}) {
void handleError(Zone self, ZoneDelegate parent, Zone zone, Object error,
StackTrace stack) {
onError(error, stack);
}
var spec = zoneSpecification == null
? ZoneSpecification(handleUncaughtError: handleError)
: ZoneSpecification.from(zoneSpecification,
handleUncaughtError: handleError);
var outer = Zone.current;
return runZoned<Future<R>>(zoneSpecification: spec, () {
FutureOr<R> result;
try {
result = action();
} catch (e, s) {
return outer.run(() => Future<R>.error(e, s));
}
if (result is Future<R>) {
var c = outer.run(() => Completer<R>.sync());
result.then(c.complete, onError: c.completeError);
return c.future;
} else {
return Future<R>.value(result);
}
});
}
void main() {
FutureOr<bool> banana() async {
Future.error("Plantain");
throw "Banana";
}
var f = catchUnhandledAsyncErrors(banana, onError: (e, s) {
print("Uncaught: $e");
});
f.catchError((e, s) {
print("Caught: $e");
return true;
});
} |
First discussed at flutter/flutter#141821 (comment)
The
runZonedGuarded
API (andrunZoned
when it is still used with the deprecatedonError
argument) is tricky to used because of the caveat that errors in the zone cannot escape that zone and a returnedFuture
from the callback may just never complete it it would have been an error.We should consider an API, here or in the core libraries, that wraps
runZonedGuarded
and does surface the first error that occurs. To start the discussion:cc @lrhn for thoughts.
The text was updated successfully, but these errors were encountered: