Módulo 03: Dart Deep Dive

Generators

Asincronia

# Generadores en Dart (sync*y async*) Los generadores son funciones especiales que permiten producir una secuencia de valores de manera perezosa (lazy). Dart soporta dos tipos: síncronos y asíncronos. ## Generadores Síncronos (`sync*`) Devuelven un `Iterable`. Generan valores bajo demanda, bloqueando la ejecución solo cuando se pide el siguiente valor. - Usan `sync*` en el cuerpo. - Usan `yield` para emitir valores. ```dart Iterable countTo(int n) sync* { print('Generador iniciado'); for (var i = 1; i <= n; i++) { print('Calculando $i...'); yield i; // Pausa aquí y entrega el valor } print('Generador terminado'); } void main() { // La función NO se ejecuta aquí final numbers = countTo(3); print('Inicio del loop'); // Se ejecuta paso a paso aquí for (final n in numbers) { print('Recibido: $n'); } } // Output: // Inicio del loop // Generador iniciado // Calculando 1... // Recibido: 1 // Calculando 2... // Recibido: 2 // ... ``` ### `yield*` (Delegación recursiva) Permite delegar la generación a otro iterable. ```dart Iterable countDownFrom(int n) sync* { if (n > 0) { yield n; yield* countDownFrom(n - 1); // Llamada recursiva eficiente } } ``` ## Generadores Asíncronos (`async*`) Devuelven un `Stream`. Son la forma más fácil de crear Streams personalizados. - Usan `async*` en el cuerpo. - Usan `yield` para emitir valores. - Pueden usar `await`. ```dart Stream timerStream() async* { for (var i = 1; i <= 3; i++) { await Future.delayed(Duration(seconds: 1)); // Espera asíncrona yield i; // Emite evento } } void main() async { await for (final tick in timerStream()) { print('Tick: $tick'); } } ``` ## Casos de Uso ### 1. Paginación de Datos Puedes crear un iterable que vaya pidiendo páginas a una API a medida que la UI las solicita. ### 2. Transformación de Datos Compleja Si tienes que procesar una lista grande pero quizás no necesites todos los resultados (ej. buscar el primer primo), un generador es más eficiente que `list.map().where()` porque no crea listas intermedias. ```dart // Eficiente: Procesa uno por uno Iterable getBigNumbers(List inputs) sync* { for (var n in inputs) { if (n > 1000) yield n; } } ``` ### 3. Gestión de Estado (BLoC) En BLoC, los eventos entran y los estados salen. `async*` es perfecto para esto. ```dart Stream mapEventToState(Event event) async* { if (event is LoginEvent) { yield LoadingState(); try { await auth.login(); yield SuccessState(); } catch (e) { yield ErrorState(e.toString()); } } } ``` ## Conclusión - Usa `sync*` para generar colecciones (`Iterable`) de manera perezosa y eficiente en memoria. - Usa `async*` para generar flujos de eventos (`Stream`) a lo largo del tiempo. - `yield` emite un valor. - `yield*` delega a otro generador.

Este apartado profundiza en los conceptos clave, proporcionando ejemplos prácticos y mejores prácticas para su aplicación en proyectos reales.

Al comprender estos detalles, podrás diseñar soluciones más robustas, mantenibles y escalables en tus aplicaciones Flutter y Dart.