Understanding async and async* in dart

Introduction:

If you’ve ever explored asynchronous dart programming language, you might have encountered async and async* keywords. They look similar and it feels they have no differences. If you use it, it even works similarly. But what is the difference? Why were Google Experts not satisfied with an async keyword that they added an asterisk symbol after async? Why are they really significant for any developer who is learning flutter? I will try to explain all the basics between async and async* in dart language.

Why Asynchronous Programming?

We use asynchronous programming to let our program complete work while waiting for another operation to finish. It is very significant while we integrate web services into our application as we have to use data coming over the internet. If there were no asynchronous programming, the performance of any app using web services would have been much slower.

Futures And Stream In Dart:

Before discussing async and async*, we must compulsory have some concepts of Futures and Streams in dart language. Future and Streams are two pillars of asynchronous programming. A future represents a future as suggested by its name. This means the data can arrive in the future because it may have to come over the internet or it may have been delayed manually. Future is generally called once until refreshed. Similarly, a Stream is a flow of data where you don’t know when the data is coming. Whenever the data comes, it will catch up immediately and show it to a user. For example, Stream is used in chat apps. You never know when the person on the other side is replying. We can’t program our apps to refresh every second or two to retrieve new messages. Stream catches the new message immediately and displays it to the user.

Async and async* in Dart:

Now we know what are futures and streams, we can learn about async and async*. Marking async and async in a dart program allows you to use the power of async/await for a Future. You add the async keyword to a function that does some work that might take a long time. It returns the result wrapped in the Future.

Future<int> doSomeTask() async {
await Future.delayed(const Duration(seconds: 2));
return 'Hello ITSNP!!';
}

Here, the function is delayed by 2 seconds and when we call this function, we get the value after 2 seconds only. Since the execution is too fast, we won’t get the required data when we call doSomeTask() function. This doesn’t solve our problem. So we can await it by marking it async while calling it.

main() async {
int response = await doSomeTask();
print(response); // prints 'Hello ITSNP' after waiting 2 seconds
}

Similarly, You add the async* keyword to make a function that returns a bunch of future values one at a time. The results are wrapped in a Stream.. async* keyword provides us extra power of using yield to return a sequence of data.

Stream<int> countForOneMinute() async* {
for (int i = 1; i <= 60; i++) {
await Future.delayed(const Duration(seconds: 1));
yield i;
}
}

Now, we can call the above function in sequence as:

main() async {
await for (int i in countForOneMinute()) {
print(i); // prints 1 to 60, one integer per second
}
}

Here, we’ve used yield instead of return because we don’t want to leave the function. We have also used await for to wait for each value yielded by Stream.

Now you might have understood async and async* to some extent. If you still have any confusion, please refer to the official documentation of Futures And Streams. If you still have any confusion, raise the query on our QNA site askitsnp.com. Keep grinding. Keep Fluttering. Keep Building. Keep Contributing.

Thank You For Reading.

Leave a Comment