Lesson 15 · 15 of 20
Streams with async* and await for · Dart
Create Dart streams with async* functions and yield, consume them with await for and transform them with where and map, using a simulated download.

A Future delivers one value; a `Stream` delivers a sequence of values over time: a download's progress, chat messages or sensor readings. The simplest way to create one is an **async* function: each yield** emits an event, and in between the function may await.
download simulates downloading 600 KB in 160 KB chunks: it waits 20 ms per chunk, adds up what has arrived without going past the total and emits the percentage. Also, nothing runs until someone listens to the stream.
`await for` walks through the stream: it waits for each event, runs the loop body and carries on until the stream closes, which here happens when the function ends. After the four progress lines, main moves on.
Streams have the same methods as lists (where, map, fold, toList…), only asynchronous: toList() returns a Future. Stream.fromIterable turns a list into a stream, and the example keeps the readings above 24 degrees. Stream.periodic emits a number every 10 ms and never ends; a `break` inside await for cancels the subscription and the stream stops.
Code · main.dart
// async* returns a Stream: each yield sends one event, over time.Stream<int> download(int totalKb, int chunkKb) async* { var received = 0; while (received < totalKb) { await Future.delayed(const Duration(milliseconds: 20)); // a network chunk received += chunkKb; if (received > totalKb) received = totalKb; yield received * 100 ~/ totalKb; }}Future<void> main() async { // await for waits for each event until the stream closes. await for (final percent in download(600, 160)) { print('Downloaded $percent%'); } // Streams have where, map, fold... like lists, but asynchronous. final readings = Stream.fromIterable([18.5, 21.0, 25.4, 30.1, 27.9]); final hot = await readings.where((t) => t > 24).map((t) => '$t C').toList(); print('Hot readings: $hot'); // A stream that never ends: break cancels the subscription. final ticks = Stream.periodic(const Duration(milliseconds: 10), (i) => i + 1); await for (final tick in ticks) { if (tick > 3) break; print('Tick $tick'); } print('Stopped listening');}Output · dart run main.dart
Downloaded 26% Downloaded 53% Downloaded 80% Downloaded 100% Hot readings: [25.4 C, 30.1 C, 27.9 C] Tick 1 Tick 2 Tick 3 Stopped listening
Key points
- A
Streamis a sequence of asynchronous values. - An
async*function creates a stream, andyieldemits each value. await forwaits for each event until the stream closes.where,mapandtoListexist for streams too.breakinsideawait forcancels the subscription.
Exercise
Create Stream<String> countdown(int from) async* that emits 3, 2, 1 and Go! with 50 ms between values, and loop over it with await for.