Wednesday, March 20, 2024

Differences and Uses of async and async* in Flutter

Introducing the Concepts of async and async* in Flutter

Flutter uses the Dart language to develop apps. Dart supports asynchronous programming, which allows multiple tasks to be processed simultaneously. One of the important concepts in asynchronous programming is the 'Future' and 'Stream'. To understand these two concepts, you need to know about the async and async* keywords.

The async keyword makes a function return a Future. A Future is an object that allows you to continue with other tasks while waiting for a task to complete. In other words, a Future represents the result of an asynchronous task.

On the other hand, the async* keyword makes a function return a Stream. A Stream is an object that can generate multiple values over time. In other words, a Stream represents a sequence of asynchronous events over time.

Now, let's look in more detail at the differences between async and async* and how each one is used.

Differences Between async and async*

Both async and async* are keywords for asynchronous programming in Dart. However, the two keywords operate in different ways and return different types of objects.

The async keyword is used to define a function that returns a Future object. This Future object represents the result of an asynchronous task, and you can continue with other tasks while waiting for this task to complete. Within an async function, you can use the 'await' keyword to wait for a Future to complete.

On the other hand, the async* keyword is used to define a function that returns a Stream object. A Stream object can generate multiple values over time. Within an async* function, you can use the 'yield' or 'yield*' keywords to add values to the Stream.

Therefore, the main difference between async and async* lies in the type of object they return and how that object is used. async is suitable for asynchronous tasks that return a single value, while async* is suitable for asynchronous tasks that generate multiple values over time.

Using async

The async keyword is used to define a function that returns a Future object. This represents the result of an asynchronous task, and you can continue with other tasks while waiting for this task to complete. Here is an example of using async.

For instance, consider a function that fetches data from the web. This function will take time to fetch the data, so it needs to be processed asynchronously. In this case, you can use async and Future.

Here is an example code using async:


Future<String> fetchData() async {
  var response = await http.get('https://example.com/data');
  if (response.statusCode == 200) {
    return response.body;
  } else {
    throw Exception('Failed to load data');
  }
}

The fetchData function above uses the async keyword to return a Future. This function calls the http.get method to fetch data from the web. Since this method returns a Future, the await keyword is used to wait for the Future to complete. Then, it checks the response status code to either return the data or throw an exception.

This is how you can easily handle asynchronous tasks using async and Future.

Using async*

The async* keyword is used to define a function that returns a Stream object. A Stream object can generate multiple values over time. Here is an example of using async*.

For instance, consider a function that generates values at a certain time interval. This function generates values over time, so it needs to be processed asynchronously. In this case, you can use async* and Stream.

Here is an example code using async*:


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

The countStream function above uses the async* keyword to return a Stream. This function generates a number every second and adds it to the Stream. This is done using the 'yield' keyword.

This is how you can easily handle asynchronous tasks that generate multiple values over time using async* and Stream.

Using async and async* Together

While async and async* are suitable for different types of asynchronous tasks, there are cases where you might need to use both keywords together. This is particularly the case when you need to fetch data from a Stream and process that data, which also takes time.

For example, consider a function that streams data from the web and processes each data item. This function needs to process the data fetching asynchronously, as well as process each data item asynchronously. In this case, you can use async and async* together.

Here is an example code using async and async* together:


Stream<Data> processData(Stream<String> rawData) async* {
  await for (var data in rawData) {
    var processedData = await process(data);
    yield processedData;
  }
}

The processData function above uses the async* keyword to return a Stream. This function fetches data from the rawData stream and processes it. This is done using an 'await for' loop. Then, it adds the processed data to the Stream using the 'yield' keyword.

This is how you can easily handle complex tasks that generate multiple values over time and process each value asynchronously by using async and async* together.

Conclusion

In this article, we looked at the differences between async and async* in Flutter, as well as how to use them. async returns a Future object and is suitable for asynchronous tasks that return a single value. On the other hand, async* returns a Stream object and is suitable for asynchronous tasks that generate multiple values over time.

We also saw how async and async* can be used together to easily handle complex tasks that generate multiple values over time and process each value asynchronously.


0 개의 댓글:

Post a Comment