Lección 15 · 15 de 20
Streams con async* y await for · Dart
Cree streams en Dart con funciones async* y yield, recórralos con await for y transfórmelos con where y map, con una descarga simulada.

Una Future da un solo valor; un `Stream` da una secuencia de valores a lo largo del tiempo: el progreso de una descarga, los mensajes de un chat o las lecturas de un sensor. La forma más sencilla de crear uno es una función **async*: cada yield** emite un evento, y entre uno y otro la función puede hacer await.
download simula la descarga de 600 KB en trozos de 160: espera 20 ms por trozo, suma lo recibido sin pasarse del total y emite el porcentaje. Además, nada se ejecuta hasta que alguien escucha el stream.
`await for` recorre el stream: espera cada evento, ejecuta el cuerpo del bucle y continúa hasta que el stream se cierra, que aquí es cuando la función termina. Después de las cuatro líneas de progreso, main sigue con lo siguiente.
Los streams tienen los mismos métodos que las listas (where, map, fold, toList…), pero asíncronos: toList() devuelve una Future. Stream.fromIterable convierte una lista en stream, y del ejemplo se quedan las lecturas de más de 24 grados. Stream.periodic emite un número cada 10 ms y no termina nunca; un `break` dentro de await for cancela la suscripción y el stream se detiene.
Código · 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');}Salida · 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
Para recordar
- Un
Streames una secuencia de valores asíncronos. - Una función
async*crea un stream, yyieldemite cada valor. await forespera cada evento hasta que el stream se cierra.where,mapytoListtambién existen para streams.breakdentro deawait forcancela la suscripción.
Ejercicio
Cree Stream<String> countdown(int from) async* que emita 3, 2, 1 y Go! con 50 ms entre cada valor, y recórralo con await for.