Future in dart: When to use async, await, and then
Asynchronous programming in dart
There are multiple ways to implement asynchronous logic in dart. Dart provides three keywords for this: async
, await
, and then
.
In this blog, we'll learn how and when to use them according to our needs.
Overview
- What is asynchronous programming?
- Asynchronous in dart
- Using
then
- Using
async-await
- Code Samples
- Conclusion
- Final Note
What is asynchronous programming?
Asynchronous programming refers to a block of code that runs in parallel with other blocks of code. As a result, we can do several things at the same time.
Source: GIPHY
For example, say we have an API request that fetches a list of recipes. This network call might take some time. During this fetching, we have a text field where a user can type into.
Our application is interacting with the user as well as fetching recipes simultaneously.
Another way to think about this is, doing some background tasks separately without disrupting the main task flow.
Asynchronous in dart
Dart gives us two ways to implement asynchronous logic:
In this blog, we'll discuss Future
.Future
class has various constructors that we can use. There are certain keywords that we need to implement when using them. The keywords are: async
, await
, and then
.
Using then
then
works on the concept of callbacks. The callback is exactly what it says it is. Calling back (executing) a block of code sometime later.
Let's say we are fetching a list of recipes. This returns a Future
.
- After the
Future
is completed (we've fetched the recipes), we want to display a message to the user. - During this fetching, we don't want to stick there but continue to execute our next block of code.
Let's look at the following code. For simplicity, we'll use print statements.
Run the code by clicking the
Run
button below.
Let's understand the code.
In line 4, we are fetching our recipes.
Here, we've used the
Future.delayed
constructor for demo purposes. Using this, we can specify the time we want to wait for (here we are waiting for 1 second).
Refer here, if you want to know more about this function.
In lines 6-8, we are giving a callback (a block of code) that is supposed to run when the recipes are fetched (or Future
is completed).
The code after line 8 should not wait for the recipes to be fetched but continue to execute.
Analyzing the output:
- The first console print statement is
start fetching recipes
as expected. - The second console print statement is
a random computation
. This is the desired result. TheFuture
takes time to complete and the rest of the code (below line 8) does not wait for it to complete but executes. - After a while,
recipes fetched
andafter fetching recipes
executes which were the callbacks for theFuture
.
So, then
fits here perfectly.
Now let's see another use case.
- After the
Future
is completed (we've fetched the recipes), we want to display a message to the user. - We want to wait for the recipes to be fetched and not execute the lines below 8.
The easiest way would be to put all the code inside the then
block.
Run the code.
We've just added everything under the then
block. Now, the a random computation
is executed after the recipes are fetched.
There's a better way to implement this use case.
Since we want to wait for the recipes to be fetched and not execute the code below, we could use simpler syntax.
And that's what async
and await
are. An alternative syntax to implement asynchronous logic.
Using async-await
Let's implement our second use case again. Run the code.
This time, we've not used any callbacks explicitly like the then
block. Instead, we've added async
in line 1 and await
in line 4.
async
keyword tells dart that this function might use asynchronous logic. Sovoid main
has theasync
keyword.await
keyword tells dart that the following statement will return aFuture
. TheFuture
should be completed and then the code below will be executed.
Let's look at some more examples.
Code Samples
As seen above, we can have multiple implementations for the same logic. Let's look at some code samples and try to simplify them.
You can run the code sample below in dartpad. Just copy-paste the code in dartpad and run it.
Sample 1
void main() async {
await Future.delayed(Duration(seconds: 1), () {
print('inside delayed');
}).then((_) {
print('inside then');
});
print('after delayed');
}
The then
block is redundant here. Since we're awaiting
the Future
, the then
callback can be implemented like a normal code of block.
Simplified:
void main() async {
await Future.delayed(Duration(seconds: 1), () {
print('inside delayed');
});
print('inside then');
print('after delayed');
}
Sample 2
void main() {
Future.delayed(Duration(seconds: 1), () {
print('inside delayed 1');
}).then((_) {
print('inside then 1');
Future.delayed(Duration(seconds: 1), () {
print('inside delayed 2');
}).then((_) {
print('inside then 2');
});
});
print('after delayed');
}
There is a nesting of then
blocks here. We can use async
, await
syntax inside a then
block also.
Simplified:
void main() {
Future.delayed(Duration(seconds: 1), () {
print('inside delayed 1');
}).then((_) async {
print('inside then 1');
await Future.delayed(Duration(seconds: 1), () {
print('inside delayed 2');
});
print('inside then 2');
});
print('after delayed');
}
I hope the examples helped in understanding the various syntaxes.
And that's it for asynchronous programming in dart using Future
.
Conclusion
- We can use
then
syntax orasync-await
syntax or both to implement asynchronous logic. - Any syntax can be used to achieve our desired result. But we should also focus on code-readability.
For further reading, you can refer to dart official docs.
Final Note
Thank you for reading this article. If you enjoyed it, consider sharing it with other people.
If you find any mistakes, please let me know.
Feel free to share your opinions below.