Go straight to the topic, guys, today I read an article about asynchronous programming in Dart. Oh, this topic sounds familiar, … well, it’s familiar, java or android have asynchronous, this girl also has it. In this article I will introduce you to futures, async and await keywords. Let’s go !!
1. Why is asynchronous programming important?
Asynchronous operations help your program get the job done while waiting for the other activity to finish. Some examples are:
- Get data from the network.
- Write data to the database.
- Read data from a file.
The following is an incorrect example of using asynchronous function ( getUserOrder () ). I will then revise this example using async and await . Please predict the results when this code is run offline:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | String createOrderMessage () { var order = getUserOrder(); return 'Your order is: $order'; } Future<String> getUserOrder() { // Imagine that this function is more complex and slow return Future.delayed(Duration(seconds: 4), () => 'Large Latte'); } main () { print(createOrderMessage()); } |
The result after running the above code is:
1 2 | I/flutter ( 5845): Your order is: Instance of 'Future<String>' |
And this is why it runs wrong:
- getUserOrder () is an asynchronous function, after getting a delay, the order “Large Latte” can be obtained.
- To get the order, the createOrderMessage () function should call getUserOrder () and wait for it to finish. But here createOderMessage () doesn’t wait for getUserOder () to finish so it gets the wrong string value.
- Here, createOrderMessage () should create an instance to wait for a job to be completed in the future. I will find out in the next section.
Pay a little attention:
- Synchoronous operation: a synchoronous operation blocks other activities from executing until it is completed.
- Synchoronous function: it only performs synchoronuos operation.
- Asynchoronous operation: it allows other operations to be performed before it completes.
- Asynchoronous function: it performs at least one asynchronous operation and can perform synchoronous operations.
2. What is the future?
A future (lowercase “f”) is an instance of the Future class. A future represents an asynchronous activity, and can have two states: Uncompleted or Completed.
- Uncompleted: when you call an asynchronous function, it returns an uncompleted future. This future is waiting for the asynchronous operation of the function to end or return an error.
- Completed: if an asynchronous action is successful, the future is completed with a value. Otherwise it completes with an error.
- Complete with a value: a future of type Future <T> completes with a value of type T. For example, a future with type Future <String> will return a string value. If a future doesn’t provide a value type, then the future is Future <void>.
- Complete with an error: if an asynchronous operation performed by a function fails for any reason then the future completes with an error.
For example, introduction to the future, please predict the result, which will it print first: “Large Latte” or “Fetching user order …”?
1 2 3 4 5 6 7 8 9 10 | Future<void> getUserOrder() { // Imagine that this function is fetching user info from another service or database return Future.delayed(Duration(seconds: 3), () => print('Large Latte')); } main() { getUserOrder(); print('Fetching user order...'); } |
The result: it will print “Fetching user order …” after 3 seconds it will print “Large Latte”.
1 2 3 4 5 6 | Performing hot restart... Syncing files to device Android SDK built for x86... I/flutter ( 5845): Fetching user order... Restarted application in 974ms. I/flutter ( 5845): Large Latte |
In a nutshell a bit:
- An Future <T> instance provides a value of type T.
- If a future does not provide a useful value, then the type of future is Future <void>.
- A future can have one of two states: uncompleted or completed.
- When an operation of the future ends, the future completes with a value or an error.
- future is an instance of Dart Future class.
3. Working with futures: async and await
The async and await keywords provide a declaration for defining asynchronous welding. There are two basic guidelines for using async and await :
- To define an asynchronous welding, we add the keyword async before the function body.
- The await keyword works only in the async function. Examples are as follows:
1 2 3 4 | main() async { // do something } |
The above function is without a return type, Dart will infer the return type itself. What about a function that has a specific return type ?, see here yyyy:
1 2 3 4 | Future<Movie> getMovie(int id) async { // do something } |
Now that you have the async function, use await to wait for it to finish in the future: print(await createOrderMessage());
See the two examples below:
Summary:
- async : You can use the async keyword before the asynchronous function body.
- async function : is a function marked by the keyword async .
- await : you can use the await keyword to get results from an asynchronous job. The await keyword is only used with the async function.
Execution flow with async and await :
- An async function runs synchronously until the first await keyword is encountered. This means that with an async function body, all code written before the await keyword is run in sync immediately.
- Prior to Dart 2.0, an async function was immediately returned, without executing any other code in the async function body.
Example of execution stream with async function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | import 'dart:async'; void createOrderMessage () async { print('Awaiting user order...'); var order = await getUserOrder(); print('Your order is: $order'); } Future<String> getUserOrder() { // Imagine that this function is more complex and slow. return Future.delayed(Duration(seconds: 4), () => 'Large Latte'); } main() async { countSeconds(4); await createOrderMessage(); } // You can ignore this function - it's here to visualize delay time in this example. void countSeconds(s) { for( var i = 1 ; i <= s; i++ ) { Future.delayed(Duration(seconds: i), () => print(i)); } } |
The result will be:
1 2 3 4 5 6 7 | Awaiting user order... 1 2 3 4 Your order is: Large Latte |
Let’s try the following one, prepare the code:
- The reportUserRole () function is given as follows, adding the following code to the function:
- Returns a successful future with the string ” User role: <user role> “. You must use the actual value returned from the getRole () function, which returns an arbitrary value. For example, the return string of the reportUserRole () function is: “User role: tester”.
- Get the user role by calling getRole () function.
1 2 3 4 5 6 | // Part 1 //You can call the provided async function getRole to return the user role Future<String> reportUserRole() async { // your implementation here } |
Compare results:
1 2 3 4 5 6 7 8 9 | // Part 1 //You can call the provided async function getRole to return the user role Future<String> reportUserRole() async { var name = await getRole(); return 'User role: $name'; } String getRolse() => 'tester'; |
4. Handling errors occur
To handle errors in async functions, we use try-catch as follows:
1 2 3 4 5 6 7 | try { var order = await getUserOrder(); print('Awaiting user order...'); } catch (err) { print('Caught error: $err'); } |
With an async function, you can write a try-catch block like in code in a synchronous function. For example async and await with * try-catch *: Test the following example to learn how to handle errors from an asynchronous function. Don’t forget to predict what the outcome will be!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | void createOrderMessage () async { try { var order = await getUserOrder(); print('Awaiting user order...'); print(order); } catch (err) { print('Caught error: $err'); } } Future<String> getUserOrder() { // Imagine that this function is more complex. var str = Future.delayed(Duration(seconds: 4), () => throw 'Cannot locate user order'); return str; } main() async { await createOrderMessage(); } |
Above is what I learned about the future , async and await . Look forward to the sequel to Fluter!