211

I am making an application using flutter framework . During this I came across with the keywords in Dart async and async*. Can anybody tell me what's the difference between them?

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
Jagraj Singh
  • 4,031
  • 4
  • 15
  • 33

5 Answers5

288

Short answer

  • async gives you a Future
  • async* gives you a Stream.

async

You add the async keyword to a function that does some work that might take a long time. It returns the result wrapped in a Future.

Future<int> doSomeLongTask() async {
  await Future.delayed(const Duration(seconds: 1));
  return 42;
}

You can get that result by awaiting the Future:

main() async {
  int result = await doSomeLongTask();
  print(result); // prints '42' after waiting 1 second
}

async*

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.

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

The technical term for this is asynchronous generator function. You use yield to return a value instead of return because you aren't leaving the function.

You can use await for to wait for each value emitted by the Stream.

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

Going on

Watch these videos to learn more, especially the one on Generators:

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
245

Marking a function as async or async* allows it to use the async/await for a Future.

The difference between both is that async* will always return a Stream and offer some syntactical sugar to emit a value through the yield keyword.

We can therefore do the following:

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

This function emits a value every second, which increments every time.

Eli Front
  • 695
  • 1
  • 8
  • 28
Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432
  • 18
    By marking a function as async* we are able to use the yield keyword and return a Stream of data. – Yash Jun 30 '20 at 06:56
19

Solution, Origins and Insights

This answer includes simplified and easy to understand examples

async

The async computation cannot provide a result immediately when it is started because the program may need to wait for an external response like:

  • Reading a file
  • Querying a database
  • Fetching data from an API

Instead of blocking all computation until the result is available, the asynchronous computation immediately returns a Future object which will eventually "complete" with the result.

Example (This type of async call can be used only without returning a response):

void main() async {
  // The next line awaits 5 seconds
  await Future.delayed(Duration(seconds: 5));
  // Pseudo API call that takes some time
  await fetchStocks();
}

Future

A Future represents a computation that doesn’t complete immediately. Whereas a normal function returns the result, an asynchronous function returns a Future, which will eventually contain the result. The Future will tell you when the result is ready.

  • Future is appended when the async function returns a value
  • Represents the result of a single computation (in contrast to a Stream)

Example:

Future<String> fetchUserOrder() =>
    // Imagine that this function is more complex and slow.
  Future.delayed(
    const Duration(seconds: 2),
        () => 'Large Latte',
  );

void main(List<String> arguments) async {
  var order = await fetchUserOrder(); 
  // App awaits 2 seconds
  print('Your $order is ready');
}

Stream

A source of asynchronous data events. A Stream provides a way to receive a sequence of events. Each event is either a data event, also called an element of the stream.

  • Stream is a sequence of results
  • From stream you get notified for results (stream elements)

async* (streams)

async* is an asynchronous generator that returns a Stream object. Made to create streams.

An example of using a stream and async*:

// Creating a new stream with async*
// Each iteration, this stream yields a number
Stream<int> createNumberStream(int number) async* {
  for (int i = 1; i <= number; i++) {
    yield i;
  }
}

void main(List<String> arguments) {
  // Calling the stream generation
  var stream = createNumberStream(5);
  // Listening to Stream yielding each number
  stream.listen((s) => print(s));
}

Result:

1
2
3
4
5

Bonus: Transforming an Existing Stream

If you already have a stream, you can transform it to a new stream based on the original stream’s events.

Example (same code as before but with a twist):

Stream<int> createNumberStream(int number) async* {
  for (int i = 1; i <= number; i++) {
    yield i;
  }
}

// This part is taking a previous stream through itself and outputs updated values
// This code multiplies each number from the stream
Stream<int> createNumberDoubling(Stream<int> chunk) async* {
  await for (final number in chunk) {
    yield number*2;
  }
}

void main(List<String> arguments) {
  // Here we are Transforming the first stream through createNumberDoubling stream generator
  var stream = createNumberDoubling(createNumberStream(5));
  stream.listen((s) => print(s));
}

Result:

2
4
6
8
10

Solution

The async and async* are close relatives, they are even from the same library dart:async The async represent a Future and a one-time exchange while the async* represents a Stream, a stream of multiple events

Stas Sorokin
  • 3,029
  • 26
  • 18
3

Async functions execute synchronously until they reach the await keyword. Therefore, all synchronous code within an async function body executes immediately.

Future<int> foo() async {
  await Future.delayed(Duration(seconds: 1));
  return 0;
}

Async* is used to create a function that returns a bunch of future values one at a time. Each result is wrapped in a Stream.

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

}

Shirsh Shukla
  • 5,491
  • 3
  • 31
  • 44
1

async* will always return a Stream

Stream<int> mainStream(int value) async* {
  for (int i = 1; i <= value; i++) {
    yield i;
  }
}

async returns the result wrapped in the Future. So it might take longer time. See the below example:

void main() async {
  // The next line awaits 10 seconds
  await Future.delayed(Duration(seconds: 10));
}
Fakhriddin Abdullaev
  • 4,169
  • 2
  • 35
  • 37