Async<T extends Object> constructor
Async<T extends Object> (
- @mustBeAnonymous @mustAwaitAllFutures Future<
T> mustAwaitAllFutures(), { - @noFutures TOnErrorCallback<
T> ? onError, - @noFutures TVoidCallback? onFinalize,
Creates an Async by executing an asynchronous function
mustAwaitAllFutures.
IMPORTANT:
Always all futures witin mustAwaitAllFutures to ensure errors are be
caught and propagated.
Implementation
factory Async(
@mustBeAnonymous
@mustAwaitAllFutures
Future<T> Function() mustAwaitAllFutures, {
@noFutures TOnErrorCallback<T>? onError,
@noFutures TVoidCallback? onFinalize,
}) {
assert(
isSubtype<T, Never>() || !isSubtype<T, Future<Object>>(),
'$T must never be a Future.',
);
return Async.result(() async {
Result<T> result;
try {
result = Ok<T>(await mustAwaitAllFutures());
} on Err catch (err) {
result = err.transfErr<T>();
} catch (error, stackTrace) {
if (onError == null) {
result = Err<T>(error, stackTrace: stackTrace);
} else {
try {
result = onError(error, stackTrace);
} on Err catch (err) {
// `onError` itself can throw an `Err` — preserve its statusCode
// and breadcrumbs rather than nesting it as another Err's value.
result = err.transfErr<T>();
} catch (error, stackTrace) {
result = Err<T>(error, stackTrace: stackTrace);
}
}
}
// Run `onFinalize` separately so its throws are absorbed into `result`
// instead of escaping the async block and leaving `Async.value` to
// reject with an uncaught error. Following standard `try/finally`
// semantics, a thrown finalize error overrides whatever `result` held.
if (onFinalize != null) {
try {
onFinalize();
} on Err catch (err) {
result = err.transfErr<T>();
} catch (error, stackTrace) {
result = Err<T>(error, stackTrace: stackTrace);
}
}
return result;
}());
}