Dart 3.10 is taking off with dot shorthands, stable build hooks, nuanced deprecation annotations, and more!Learn more
dart:async
Asynchronous programming often uses callback functions, but Dart provides alternatives:Future andStream objects. A Future is like a promise for a result to be provided sometime in the future. A Stream is a way to get a sequence of values, such as events. Future, Stream, and more are in the dart:async library (API reference).
You don't always need to use the Future or Stream APIs directly. The Dart language supports asynchronous coding using keywords such asasync andawait. Check out theasynchronous programming tutorial for details.
The dart:async library works in both web apps and command-line apps. To use it, import dart:async:
import'dart:async';You don't need to import dart:async to use the Future and Stream APIs, because dart:core exports those classes.
Future
#Future objects appear throughout the Dart libraries, often as the object returned by an asynchronous method. When a futurecompletes, its value is ready to use.
Using await
# Before you directly use the Future API, consider usingawait instead. Code that usesawait expressions can be easier to understand than code that uses the Future API.
Consider the following function. It uses Future'sthen() method to execute three asynchronous functions in a row, waiting for each one to complete before executing the next one.
voidrunUsingFuture(){// ...findEntryPoint().then((entryPoint){returnrunExecutable(entryPoint,args);}).then(flushThenExit);}The equivalent code with await expressions looks more like synchronous code:
Future<void>runUsingAsyncAwait()async{// ...varentryPoint=awaitfindEntryPoint();varexitCode=awaitrunExecutable(entryPoint,args);awaitflushThenExit(exitCode);} Anasync function can catch exceptions from Futures. For example:
varentryPoint=awaitfindEntryPoint();try{varexitCode=awaitrunExecutable(entryPoint,args);awaitflushThenExit(exitCode);}catch(e){// Handle the error...} Async functions return Futures. If you don't want your function to return a future, then use a different solution. For example, you might call anasync function from your function.
For more information on usingawait and related Dart language features, see theasynchronous programming tutorial.
Basic usage
# You can usethen() to schedule code that runs when the future completes. For example,Client.read() returns a Future, since HTTP requests can take a while. Usingthen() lets you run some code when that Future has completed and the promised string value is available:
httpClient.read(url).then((Stringresult){print(result);}); UsecatchError() to handle any errors or exceptions that a Future object might throw.
httpClient.read(url).then((Stringresult){print(result);}).catchError((e){// Handle or ignore the error.}); Thethen().catchError() pattern is the asynchronous version oftry-catch.
Be sure to invokecatchError() on the result ofthen()—not on the result of the originalFuture. Otherwise, thecatchError() can handle errors only from the original Future's computation, but not from the handler registered bythen().
Chaining multiple asynchronous methods
# Thethen() method returns a Future, providing a useful way to run multiple asynchronous functions in a certain order. If the callback registered withthen() returns a Future,then() returns a Future that will complete with the same result as the Future returned from the callback. If the callback returns a value of any other type,then() creates a new Future that completes with the value.
Futureresult=costlyQuery(url);result.then((value)=>expensiveWork(value)).then((_)=>lengthyComputation()).then((_)=>print('Done!')).catchError((exception){/* Handle exception...*/});In the preceding example, the methods run in the following order:
costlyQuery()expensiveWork()lengthyComputation()
Here is the same code written using await:
try{finalvalue=awaitcostlyQuery(url);awaitexpensiveWork(value);awaitlengthyComputation();print('Done!');}catch(e){/* Handle exception...*/}Waiting for multiple futures
#Sometimes your algorithm needs to invoke many asynchronous functions and wait for them all to complete before continuing. Use theFuture.wait() static method to manage multiple Futures and wait for them to complete:
Future<void>deleteLotsOfFiles()async=>...Future<void>copyLotsOfFiles()async=>...Future<void>checksumLotsOfOtherFiles()async=>...awaitFuture.wait([deleteLotsOfFiles(),copyLotsOfFiles(),checksumLotsOfOtherFiles(),]);print('Done with all the long steps!');Future.wait() returns a future which completes once all the provided futures have completed. It completes either with their results, or with an error if any of the provided futures fail.
Handling errors for multiple futures
#You can also wait for parallel operations on:
These extensions return aFuture with the resulting values of all provided futures. UnlikeFuture.wait, they also let you handle errors.
If any future in the collection completes with an error,wait completes with aParallelWaitError. This allows the caller to handle individual errors and dispose of successful results if necessary.
When youdon't need the result values from each future, usewait on aniterable of futures:
Future<int>delete()async=>...;Future<String>copy()async=>...;Future<bool>errorResult()async=>...;voidmain()async{try{// Wait for each future in a list, returns a list of futures:varresults=await[delete(),copy(),errorResult()].wait;}onParallelWaitError<List<bool?>,List<AsyncError?>>catch(e){print(e.values[0]);// Prints successful futureprint(e.values[1]);// Prints successful futureprint(e.values[2]);// Prints null when the result is an errorprint(e.errors[0]);// Prints null when the result is successfulprint(e.errors[1]);// Prints null when the result is successfulprint(e.errors[2]);// Prints error}} When youdo need the individual result values from each future, usewait on arecord of futures. This provides the additional benefit that the futures can be of different types:
Future<int>delete()async=>...;Future<String>copy()async=>...;Future<bool>errorResult()async=>...;voidmain()async{try{// Wait for each future in a record.// Returns a record of futures that you can destructure.final(deleteInt,copyString,errorBool)=await(delete(),copy(),errorResult()).wait;// Do something with the results...}onParallelWaitError<(int?,String?,bool?),(AsyncError?,AsyncError?,AsyncError?)>catch(e){// ...}}Stream
#Stream objects appear throughout Dart APIs, representing sequences of data. For example, HTML events such as button clicks are delivered using streams. You can also read a file as a stream.
Using an asynchronous for loop
# Sometimes you can use an asynchronous for loop (await for) instead of using the Stream API.
Consider the following function. It uses Stream'slisten() method to subscribe to a list of files, passing in a function literal that searches each file or directory.
voidmain(List<String>arguments){// ...FileSystemEntity.isDirectory(searchPath).then((isDir){if(isDir){finalstartingDir=Directory(searchPath);startingDir.list().listen((entity){if(entityisFile){searchFile(entity,searchTerms);}});}else{searchFile(File(searchPath),searchTerms);}});} The equivalent code with await expressions, including an asynchronous for loop (await for), looks more like synchronous code:
voidmain(List<String>arguments)async{// ...if(awaitFileSystemEntity.isDirectory(searchPath)){finalstartingDir=Directory(searchPath);awaitfor(finalentityinstartingDir.list()){if(entityisFile){searchFile(entity,searchTerms);}}}else{searchFile(File(searchPath),searchTerms);}} Before usingawait for, make sure that it makes the code clearer and that you really do want to wait for all of the stream's results. For example, you usually shouldnot useawait for for DOM event listeners, because the DOM sends endless streams of events. If you useawait for to register two DOM event listeners in a row, then the second kind of event is never handled.
For more information on usingawait and related Dart language features, see theasynchronous programming tutorial.
Listening for stream data
# To get each value as it arrives, either useawait for or subscribe to the stream using thelisten() method:
// Add an event handler to a button.submitButton.onClick.listen((e){// When the button is clicked, it runs this code.submitData();}); In this example, theonClick property is aStream object provided by the submit button.
If you care about only one event, you can get it using a property such asfirst,last, orsingle. To test the event before handling it, use a method such asfirstWhere(),lastWhere(), orsingleWhere().
If you care about a subset of events, you can use methods such asskip(),skipWhile(),take(),takeWhile(), andwhere().
Transforming stream data
# Often, you need to change the format of a stream's data before you can use it. Use thetransform() method to produce a stream with a different type of data:
varlines=inputStream.transform(utf8.decoder).transform(constLineSplitter());This example uses two transformers. First it uses utf8.decoder to transform the stream of integers into a stream of strings. Then it uses a LineSplitter to transform the stream of strings into a stream of separate lines. These transformers are from the dart:convert library (see thedart:convert section).
Handling errors and completion
# How you specify error and completion handling code depends on whether you use an asynchronous for loop (await for) or the Stream API.
If you use an asynchronous for loop, then use try-catch to handle errors. Code that executes after the stream is closed goes after the asynchronous for loop.
Future<void>readFileAwaitFor()async{varconfig=File('config.txt');Stream<List<int>>inputStream=config.openRead();varlines=inputStream.transform(utf8.decoder).transform(constLineSplitter());try{awaitfor(finallineinlines){print('Got${line.length} characters from stream');}print('file is now closed');}catch(e){print(e);}} If you use the Stream API, then handle errors by registering anonError listener. Run code after the stream is closed by registering anonDone listener.
varconfig=File('config.txt');Stream<List<int>>inputStream=config.openRead();inputStream.transform(utf8.decoder).transform(constLineSplitter()).listen((Stringline){print('Got${line.length} characters from stream');},onDone:(){print('file is now closed');},onError:(e){print(e);},);More information
#For some examples of using Future and Stream in command-line apps, check out thedart:io documentation. Also see these articles and tutorials:
Unless stated otherwise, the documentation on this site reflects Dart 3.10.0. Page last updated on 2025-5-5.View source orreport an issue.