then<U> method
Register callbacks to be called when this future completes.
When this future completes with a value,
the onValue
callback will be called with that value.
If this future is already completed, the callback will not be called
immediately, but will be scheduled in a later microtask.
If onError
is provided, and this future completes with an error,
the onError
callback is called with that error and its stack trace.
The onError
callback must accept either one argument or two arguments
where the latter is a StackTrace.
If onError
accepts two arguments,
it is called with both the error and the stack trace,
otherwise it is called with just the error object.
The onError
callback must return a value or future that can be used
to complete the returned future, so it must be something assignable to
FutureOr<R>
.
Returns a new Future
which is completed with the result of the call to onValue
(if this future completes with a value)
or to onError
(if this future completes with an error).
If the invoked callback throws,
the returned future is completed with the thrown error
and a stack trace for the error.
In the case of onError
,
if the exception thrown is identical
to the error argument to onError
,
and it is thrown synchronously
the throw is considered a rethrow,
and the original stack trace is used instead.
To rethrow with the same stack trace in an asynchronous callback,
use Error.throwWithStackTrace.
If the callback returns a Future,
the future returned by then
will be completed with
the same result as the future returned by the callback.
If onError
is not given, and this future completes with an error,
the error is forwarded directly to the returned future.
In most cases, it is more readable to use catchError separately,
possibly with a test
parameter,
instead of handling both value and error in a single then call.
Note that futures don't delay reporting of errors until listeners are
added. If the first then
or catchError
call happens
after this future has completed with an error,
then the error is reported as unhandled error.
See the description on Future.
Implementation
@override
Future<U> then<U>(
FutureOr<U> Function(T value) onValue, {
Function? onError,
}) async {
if (onError != null &&
onError is! Function(Object, StackTrace) &&
onError is! Function(Object)) {
throw ArgumentError.value(
onError,
"onError",
"Error handler must accept one Object or one Object and a StackTrace"
" as arguments, and return a value of the returned future's type",
);
}
try {
final response = await _execute();
return onValue(response as T);
} catch (error, stack) {
final FutureOr<U> result;
if (onError != null) {
if (onError is Function(Object, StackTrace)) {
result = onError(error, stack);
} else if (onError is Function(Object)) {
result = onError(error);
} else {
throw ArgumentError.value(
onError,
"onError",
"Error handler must accept one Object or one Object and a StackTrace"
" as arguments, and return a value of the returned future's type",
);
}
// Give better error messages if the result is not a valid
// FutureOr<R>.
try {
return result;
} on TypeError {
throw ArgumentError(
"The error handler of Future.then"
" must return a value of the returned future's type",
"onError");
}
}
rethrow;
}
}