Asynchronous programming: futures, async, await
- Why asynchronous code matters
- What is a future?
- Working with futures: async and await
- Handling errors
- Exercise: Putting it all together
- Which lints work for futures?
- What's next?
This tutorial teaches you how to write asynchronous code using futures and the async
and await
keywords. Using embedded DartPad editors, you can test your knowledge by running example code and completing exercises.
To get the most out of this tutorial, you should have the following:
- Knowledge of basic Dart syntax.
- Some experience writing asynchronous code in another language.
- The
discarded_futures
andunawaited_futures
lints enabled.
This tutorial covers the following material:
- How and when to use the
async
andawait
keywords. - How using
async
andawait
affects execution order. - How to handle errors from an asynchronous call using
try-catch
expressions inasync
functions.
Estimated time to complete this tutorial: 40-60 minutes.
The exercises in this tutorial have partially completed code snippets. You can use DartPad to test your knowledge by completing the code and clicking the Run button. Don't edit the test code in the main
function or below.
If you need help, expand the Hint or Solution dropdown after each exercise.
Why asynchronous code matters
#Asynchronous operations let your program complete work while waiting for another operation to finish. Here are some common asynchronous operations:
- Fetching data over a network.
- Writing to a database.
- Reading data from a file.
Such asynchronous computations usually provide their result as a Future
or, if the result has multiple parts, as a Stream
. These computations introduce asynchrony into a program. To accommodate that initial asynchrony, other plain Dart functions also need to become asynchronous.
To interact with these asynchronous results, you can use the async
and await
keywords. Most asynchronous functions are just async Dart functions that depend, possibly deep down, on an inherently asynchronous computation.
Example: Incorrectly using an asynchronous function
#The following example shows the wrong way to use an asynchronous function (fetchUserOrder()
). Later you'll fix the example using async
and await
. Before running this example, try to spot the issue -- what do you think the output will be?
// This example shows how *not* to write asynchronous Dart code.
String createOrderMessage() {
var order = fetchUserOrder();
return 'Your order is: $order';
}
Future<String> fetchUserOrder() =>
// Imagine that this function is more complex and slow.
Future.delayed(const Duration(seconds: 2), () => 'Large Latte');
void main() {
print(createOrderMessage());
}
Here's why the example fails to print the value that fetchUserOrder()
eventually produces:
fetchUserOrder()
is an asynchronous function that, after a delay, provides a string that describes the user's order: a "Large Latte".- To get the user's order,
createOrderMessage()
should callfetchUserOrder()
and wait for it to finish. BecausecreateOrderMessage()
does not wait forfetchUserOrder()
to finish,createOrderMessage()
fails to get the string value thatfetchUserOrder()
eventually provides. - Instead,
createOrderMessage()
gets a representation of pending work to be done: an uncompleted future. You'll learn more about futures in the next section. - Because
createOrderMessage()
fails to get the value describing the user's order, the example fails to print "Large Latte" to the console, and instead prints "Your order is: Instance of '_Future<String>'".
In the next sections you'll learn about futures and about working with futures (using async
and await
) so that you'll be able to write the code necessary to make fetchUserOrder()
print the desired value ("Large Latte") to the console.
What is a future?
#A future (lower case "f") is an instance of the Future (capitalized "F") class. A future represents the result of an asynchronous operation, and can have two states: uncompleted or completed.
Uncompleted
#When you call an asynchronous function, it returns an uncompleted future. That future is waiting for the function's asynchronous operation to finish or to throw an error.
Completed
#If the asynchronous operation succeeds, the future completes with a value. Otherwise, it completes with an error.
Completing with a value
#A future of type Future<T>
completes with a value of type T
. For example, a future with type Future<String>
produces a string value. If a future doesn't produce a usable value, then the future's type is Future<void>
.
Completing with an error
#If the asynchronous operation performed by the function fails for any reason, the future completes with an error.
Example: Introducing futures
#In the following example, fetchUserOrder()
returns a future that completes after printing to the console. Because it doesn't return a usable value, fetchUserOrder()
has the type Future<void>
. Before you run the example, try to predict which will print first: "Large Latte" or "Fetching user order...".
Future<void> fetchUserOrder() {
// Imagine that this function is fetching user info from another service or database.
return Future.delayed(const Duration(seconds: 2), () => print('Large Latte'));
}
void main() {
fetchUserOrder();
print('Fetching user order...');
}
In the preceding example, even though fetchUserOrder()
executes before the print()
call on line 8, the console shows the output from line 8("Fetching user order...") before the output from fetchUserOrder()
("Large Latte"). This is because fetchUserOrder()
delays before it prints "Large Latte".
Example: Completing with an error
#Run the following example to see how a future completes with an error. A bit later you'll learn how to handle the error.
Future<void> fetchUserOrder() {
// Imagine that this function is fetching user info but encounters a bug.
return Future.delayed(
const Duration(seconds: 2),
() => throw Exception('Logout failed: user ID is invalid'),
);
}
void main() {
fetchUserOrder();
print('Fetching user order...');
}
In this example, fetchUserOrder()
completes with an error indicating that the user ID is invalid.
You've learned about futures and how they complete, but how do you use the results of asynchronous