The result of an asynchronous computation.
Anasynchronous computation cannot provide a result immediatelywhen it is started, unlike a synchronous computation which does computea result immediately by either returning a value or by throwing.An asynchronous computation may need to wait for something externalto the program (reading a file, querying a database, fetching a web page)which takes time.Instead of blocking all computation until the result is available,the asynchronous computation immediately returns aFuturewhich willeventually "complete" with the result.
Asynchronous programming
To perform an asynchronous computation, you use anasync functionwhich always produces a future.Inside such an asynchronous function, you can use theawait operationto delay execution until another asynchronous computation has a result.While execution of the awaiting function is delayed,the program is not blocked, and can continue doing other things.
Example:
import "dart:io";Future<bool> fileContains(String path, String needle) async { var haystack = await File(path).readAsString(); return haystack.contains(needle);}Here theFile.readAsString method fromdart:io is an asynchronousfunction returning aFuture<String>.ThefileContains function is marked withasync right before its body,which means that you can useawait inside it,and that it must return a future.The call toFile(path).readAsString() initiates reading the file intoa string and produces aFuture<String> which will eventually contain theresult.Theawait then waits for that future to complete with a string(or an error, if reading the file fails).While waiting, the program can do other things.When the future completes with a string, thefileContains functioncomputes a boolean and returns it, which then completes the originalfuture that it returned when first called.
If a future completes with anerror, awaiting that future will(re-)throw that error. In the example here, we can add error checking:
import "dart:io";Future<bool> fileContains(String path, String needle) async { try { var haystack = await File(path).readAsString(); return haystack.contains(needle); } on FileSystemException catch (exception, stack) { _myLog.logError(exception, stack); return false; }}You use a normaltry/catch to catch the failures of awaitedasynchronous computations.
In general, when writing asynchronous code, you should always await afuture when it is produced, and not wait until after another asynchronousdelay. That ensures that you are ready to receive any error that thefuture might produce, which is important because an asynchronous errorthat no-one is awaiting is anuncaught error and may terminatethe running program.
Programming with theFuture API.
TheFuture class also provides a more direct, low-level functionalityfor accessing the result that it completes with.Theasync andawait language features are built on top of thisfunctionality, and it sometimes makes sense to use it directly.There are things that you cannot do by justawaiting one future ata time.
With aFuture, you can manually register callbacksthat handle the value, or error, once it is available.For example:
Future<int> future = getFuture();future.then((value) => handleValue(value)) .catchError((error) => handleError(error));Since aFuture can be completed in two ways,either with a value (if the asynchronous computation succeeded)or with an error (if the computation failed),you can install callbacks for either or both cases.
In some cases we say that a future is completedwith another future.This is a short way of stating that the future is completed in the same way,with the same value or error,as the other future once that other future itself completes.Most functions in the platform libraries that complete a future(for exampleCompleter.complete orFuture.value),also accepts another future, and automatically handles forwardingthe result to the future being completed.
The result of registering callbacks is itself aFuture,which in turn is completed with the result of invoking thecorresponding callback with the original future's result.The new future is completed with an error if the invoked callback throws.For example:
Future<int> successor = future.then((int value) { // Invoked when the future is completed with a value. return 42; // The successor is completed with the value 42. }, onError: (e) { // Invoked when the future is completed with an error. if (canHandle(e)) { return 499; // The successor is completed with the value 499. } else { throw e; // The successor is completed with the error e. } });If a future does not have any registered handler when it completeswith an error, it forwards the error to an "uncaught-error handler".This behavior ensures that no error is silently dropped.However, it also means that error handlers should be installed early,so that they are present as soon as a future is completed with an error.The following example demonstrates this potential bug:
var future = getFuture();Timer(const Duration(milliseconds: 5), () { // The error-handler is not attached until 5 ms after the future has // been received. If the future fails before that, the error is // forwarded to the global error-handler, even though there is code // (just below) to eventually handle the error. future.then((value) { useValue(value); }, onError: (e) { handleError(e); });});When registering callbacks, it's often more readable to register the twocallbacks separately, by first usingthen with one argument(the value handler) and using a secondcatchError for handling errors.Each of these will forward the result that they don't handleto their successors, and together they handle both value and error result.It has the additional benefit of thecatchError handling errors in thethen value callback too.Using sequential handlers instead of parallel ones often leads to code thatis easier to reason about.It also makes asynchronous code very similar to synchronous code:
// Synchronous code.try { int value = foo(); return bar(value);} catch (e) { return 499;}Equivalent asynchronous code, based on futures:
Future<int> asyncValue = Future(foo); // Result of foo() as a future.asyncValue.then((int value) { return bar(value);}).catchError((e) { return 499;});Similar to the synchronous code, the error handler (registered withcatchError) is handling any errors thrown by eitherfoo orbar.If the error-handler had been registered as theonError parameter ofthethen call, it would not catch errors from thebar call.
Futures can have more than one callback-pair registered. Each successor istreated independently and is handled as if it was the only successor.The order in which the individual successors are completed is undefined.
A future may also fail to ever complete. In that case, no callbacks arecalled. That situation should generally be avoided if possible, unlessit's very clearly documented.
- Available extensions
- Annotations
- @vmIsolateUnsendable
Constructors
- Future.new(FutureOr<
T> computation()) - Creates a future containing the result of calling
computationasynchronously withTimer.run.factory - Future.delayed(Durationduration, [FutureOr<
T> computation()?]) - Creates a future that runs its computation after a delay.factory
- Future.error(Objecterror, [StackTrace?stackTrace])
- Creates a future that completes with an error.factory
- Future.microtask(FutureOr<
T> computation()) - Creates a future containing the result of calling
computationasynchronously withscheduleMicrotask.factory - Future.sync(FutureOr<
T> computation()) - Returns a future containing the result of immediately calling
computation.factory - Future.value([FutureOr<
T> ?value]) - Creates a future completed with
value.factory
Properties
- hashCode→int
- The hash code for this object.no setterinherited
- runtimeType→Type
- A representation of the runtime type of the object.no setterinherited
- toJS→JSPromise<
T> Available onFuture<
AJSPromise that either resolves with the result of the completedFuture or rejects with an object that contains its error.T> , provided by theFutureOfJSAnyToJSPromise extensionno setter- toJS→JSPromise<
JSAny?> Available onFuture<
AJSPromise that either resolves once thisFuture completes or rejectswith an object that contains its error.void> , provided by theFutureOfVoidToJSPromise extensionno setter
Methods
- asStream(
)→Stream< T> - Creates aStream containing the result of this future.
- catchError(
FunctiononError, {booltest(Objecterror)?})→Future< T> - Handles errors emitted by thisFuture.
- ignore(
)→ void Available onFuture<
Completely ignores this future and its result.T> , provided by theFutureExtensions extension- noSuchMethod(
Invocationinvocation)→ dynamic - Invoked when a nonexistent method or property is accessed.inherited
- onError<
E extendsObject> (FutureOr< T> handleError(Eerror,StackTracestackTrace), {booltest(Eerror)?})→Future<T> Available onFuture<
Handles errors on this future.T> , provided by theFutureExtensions extension- then<
R> (FutureOr< R> onValue(Tvalue), {Function?onError})→Future<R> - Register callbacks to be called when this future completes.
- timeout(
DurationtimeLimit, {FutureOr< T> onTimeout()?})→Future<T> - Stop waiting for this future after
timeLimithas passed. - toString(
)→String - A string representation of this object.inherited
- whenComplete(
FutureOr< void> action())→Future<T> - Registers a function to be called when this future completes.
Operators
- operator ==(
Objectother)→bool - The equality operator.inherited
Static Methods
- any<
T> (Iterable< Future< futures)→Future<T> >T> - Returns the result of the first future in
futuresto complete. - doWhile(
FutureOr< bool> action())→Future<void> - Performs an operation repeatedly until it returns
false. - forEach<
T> (Iterable< T> elements,FutureOraction(Telement))→Future<void> - Performs an action for each element of the iterable, in turn.
- wait<
T> (Iterable< Future< futures, {booleagerError =false,voidcleanUp(TsuccessValue)?})→Future<T> >List< T> > - Waits for multiple futures to complete and collects their results.