Learn about the Dart language – Part X

Tram Ho

This codelab teaches you how to write asynchronous code using Future, async and await keywords. Using the DartPad editor, you can test your knowledge by running the example code and completing exercises.

This codelab includes the following documents:

  • How and when to use async and await keywords.
  • The use of async and await affects the order of execution.
  • How to handle errors from asynchronous calls using the try-catch expression in asynchronous functions.

Why is asynchronous code important

Asynchronous tasks allow your program to finish the job while waiting for another task to finish. Here are some common asynchronous tasks:

  • Get data online.
  • Write to the database.
  • Read data from a file. To perform asynchronous tasks in Dart, you can use the Future class and the keyword async and await.

Example: Using the asynchronous function in the wrong way

The following example shows how to use the asynchronous fetchUserOrder () function. You will then correct the example using async and await. Before running this example, try to spot the problem – what do you think the output will be?

This is why the above example cannot print the value that fetchUserOrder () eventually generates:

  • fetchUserOrder () is an asynchronous function, after a period of time returns a string describing the user’s order.
  • To receive user orders, createOrderMessage () should call fetchUserOrder () and wait until it finishes. Because createOrderMessage () does not wait for fetchUserOrder () to finish, createOrderMessage () does not receive the string value that eventually fetchUserOrder () provides.
  • Instead, createOrderMessage () will show the pending work: an unfinished Future.
  • Because createOrderMessage () does not receive the value that describes the user’s order, this example cannot print the result and instead prints “Your order is: Instance of ‘_Future'”

Things to remember:

  • Sync task : A synchronization task prevents other tasks from executing until it is completed.
  • Sync function: A synchronous function only performs synchronous tasks.
  • Asynchronous task : Once started, an asynchronous task allows other tasks to be performed before completion.
  • Asynchronous functions: Asynchronous functions perform at least one asynchronous task and can also perform synchronous tasks.


Future represents the result of an asynchronous task and can have two states: unfinished or completed.

Note: Incomplete is a Dart term that refers to the state of a Future before it creates a value.


When you call an asynchronous function, it returns an unfinished Future. That future is waiting for the asynchronous task of the function to end or issue an error.


If the asynchronous task succeeds, Future completes with a value. If not, it completes with an error.

Complete with a value

Future of type Future <T> completes with value of type T. For example, a Future with type Future <String> creates a String value. If a Future does not create usable value, then the Future type <void> is Future <void>.

Complete with an error

If the asynchronous operation performed by the function fails for any reason, Future will complete with an error.

Example: Introducing Future

In the following example, fetchUserOrder () returns a completed Future after printing to the console. Because it does not return usable values, fetchUserOrder () has the type Future <void>. Before you run the example, try to predict which one will print first:

In the previous example, although fetchUserOrder () executed before print () on line 8, the console displayed the output from line 8 (“Fetching user order …”) before fetchUserOrder () (“Large Latte”) results. This is because fetchUserOrder () is delayed.

Example: Complete with an error

Run the following example to see how Future completes with an error.

In this example, fetchUserOrder () completed with an error indicating an invalid user ID.

We have learned about Future and how it is done, but how to use the results of asynchronous functions? In the next section, we will learn how to get results with async and await keywords.

Review fast:

  • Future <T> creates value of type T
  • If a Future does not create usable values, use the Future type <void>.
  • A Future can be in one of two states: unfinished or completed.
  • When you call a function that returns a Future, the function will queue the work to be performed and return an unfinished Future.
  • When the task of a Future ends, Future completes with a value or an error.

Working with Future: async and await

The async and await keywords provide a declaration for defining asynchronous functions and using their results. Remember these two basic principles when using async and await:

  • To define a function as async, add async before the function body
  • The await keyword only works in async functions. Below is an example to convert main () function from synchronous function to asynchronous function.

First, add the async keyword before the function body:

If the function with the return type is declared, update the type to Future <T>, where T is the value type that the function returns. If the function doesn’t explicitly return a value, the return type is Future <void>:

Now that you have the asynchronous function, you can use the await keyword to wait for Future to complete:

As the following two examples show, the async and await keywords lead to asynchronous code that looks very much like synchronous code. The only difference is highlighted in the following example:

For example, the synchronization function


For example, asynchronous functions


The asynchronous example differs in three ways:

  • The return type for createOrderMessage () changed from String to Future <String>.
  • The async keyword appears before the function body of createOrderMessage () and main ().
  • The await keyword appears before calling asynchronous functions fetchUserOrder () and createOrderMessage ().

Things to remember:

  • async: You can use the async keyword before the body of the function to mark it asynchronous.
  • Async function: async function is a function labeled with the keyword async.
  • await: You can use the await keyword to get the complete result of an asynchronous expression. The await keyword only works in an async function.

Threads execute with async and await

The async function runs synchronously until the first await keyword is encountered. This means that in an async function body, all code synchronizes before the first await keyword executes immediately.

Version notes: Prior to Dart 2.0, an async function returned immediately without executing any code in the async function body.

Example: Execute in async functions

Run the following example to see how this is done in the async function body. What do you think the output will be?

After running the code in the previous example, try reversing lines 2 and 3:

Notice that the time of the outputs has changed, now, print('Awaiting user order') appears after the first await keyword in printOrderMessage() .

Error handling

To handle errors in asynchronous functions, use try-catch:

In the async function, you can write catch statements the same way you do in synchronous code.

For example, async and await with try-catch Run the following example to see how to handle errors from asynchronous functions. What do you think the output will be?

Source: https://dart.dev/codelabs/async-await

Share the news now

Source : Viblo