Dart's async/await in Flutter

The async and await approaches in Dart are very similar to other languages (looking at you C#), which makes it a comfortable topic to grasp for those who have used this pattern before. However, even if you don’t have experience with asynchronous programming using async/await, you should find it easy to follow along here. Do keep in mind that this article assumes at least a basic familiarity with asynchronous programming.

In a nutshell, you have two keywords to understand - async and await. Any functions you want to run asynchronously need to have the async modifier added to it. This modifier comes right after the function signature, like this:

void hello() async {
  print('something exciting is going to happen here...');
}

This is, of course, a contrived example. Typically, the function you want to run asynchronously would have some expensive operation in it like file I/O (an API call to a RESTful service)or some sort of more common computation. Don’t worry, we’ll cover more complex scenarios in a bit…

First, we come to await. The await part basically says  -  go ahead and run this function asynchronously and, when it is done, continue on to the next line of code. This is the best part of using async/await, you can write code that is very easy to follow, like this:

void main() async {
  await hello();
  print('all done');
}

There are two important things to grasp concerning the block of code above. First off, we use the async modifier on the main method because we are going to run the hello() function asynchronously.

Secondly, we place the await modifier directly in front of our asynchronous function. Hence, this is frequently referred to as the async/await pattern.

Just remember, if you are going to use await, make sure that both the caller function and any functions you call within that function all use the async modifier.

How does this work under the hood?

So, how exactly does Dart make all this work? To really grasp this, you need to understand Dart futures. You can skip this section if you want and still use the pattern discussed above, but it does help to have the knowledge of how and why it works. So here are the finer points of how async and await work in Dart.

When you await an asynchronous function, the execution of the code within the caller suspends while the async operation is executed. When the operation is completed, the value of what was awaited is contained within a Future object.

Take a look at the simple program below. We assign the result of the asynchronous function four() to the variable x. Then, we print out its number to prove we got the expected result.

import 'dart:async';
void main() async {
var x = await four();
print(x);
}
Future<int> four() async {
return 4;
}

A more realistic example

So far, I have shown you contrived examples that never really needed to be asynchronous. This was done to keep things as simple as possible. Now, let’s do some realistic async/await work.

Typically, the reason you would want to do async programming is if you knew that you were going to perform a long-running operation, and you didn’t want your program to be unresponsive while said operation was running. Let’s create a long-running operation (2 seconds) and do it async.

import 'dart:async';
class Employee {
int id;
String firstName;
String lastName;
Employee(this.id, this.firstName, this.lastName);
}
void main() async {
print("getting employee...");
var x = await getEmployee(33);
print("Got back ${x.firstName} ${x.lastName} with id# ${x.id}");
}
Future<Employee> getEmployee(int id) async {
//Simluate what a real service call delay may look like by delaying 2 seconds
await Future<Employee>.delayed(const Duration(seconds: 2));
//and then return an employee - lets pretend we grabbed this out of a database 🙂
var e = new Employee(id, "Joe", "Coder");
return e;
}

If you run the above code, you will see the message “getting employee…” print out immediately. Then, two seconds later, the employee arrives back and the details of that employee are printed out.

Multiple async calls

In some languages, having to make multiple async calls can be a real headache if they don’t support the async/await pattern. This is because, typically, you would make the first async call and, within its callback, nest another async call, and so on… This is referred to as “callback hell”. However, with async/await, you make the calls linearly and without nesting - just like you would in any non-async code.

Consider the example below, we have three async methods and we want to asynchronously call them, one at a time, in order.

import 'dart:async';
Future<String> firstAsync() async {
await Future<String>.delayed(const Duration(seconds: 2));
return "First!";
}
Future<String> secondAsync() async {
await Future<String>.delayed(const Duration(seconds: 2));
return "Second!";
}
Future<String> thirdAsync() async {
await Future<String>.delayed(const Duration(seconds: 2));
return "Third!";
}
void main() async {
var f = await firstAsync();
print(f);
var s = await secondAsync();
print(s);
var t = await thirdAsync();
print(t);
print('done');
}

If you were to run the above program, you would see the following result shown in your console (note the two second delay as well between each call):

First!

Second!

Third!

done

Free Resources