What's the difference between async and async* in Dart?

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

The difference between both is that async* will always returns a Stream and offer some syntax sugar to emit a value through 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, that increment every time


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:

  • Isolates and Event Loops
  • Futures
  • Streams
  • async / await
  • Generators

Tags:

Dart

Flutter