Módulo 03: Dart Deep Dive

Futures

Asincronia

# Futures y Async/Await en Dart Un **Future** representa el resultado de una operación asíncrona que se completará en algún momento con un valor o un error. ## Estados de un Future 1. **Uncompleted (Pendiente):** La operación está en curso. 2. **Completed (Completado):** - **Con valor:** Éxito (`then`). - **Con error:** Fallo (`catchError`). ## Sintaxis: `then` vs `async/await` ### Estilo Clásico (Callback Hell) ```dart void fetchUser() { print('Iniciando...'); getUserName().then((name) { print('Nombre: $name'); return getUserId(name); }).then((id) { print('ID: $id'); }).catchError((error) { print('Error: $error'); }).whenComplete(() { print('Finalizado'); }); } ``` ### Estilo Moderno (Async/Await) Mucho más legible, parece código síncrono. ```dart Future fetchUser() async { print('Iniciando...'); try { final name = await getUserName(); print('Nombre: $name'); final id = await getUserId(name); print('ID: $id'); } catch (error) { print('Error: $error'); } finally { print('Finalizado'); } } ``` ## Future Constructors ### `Future.value` y `Future.error` Para crear futures que se completan inmediatamente. ```dart Future getCachedData() { if (cache.hasData) { return Future.value(cache.data); } return fetchDataFromServer(); } ``` ### `Future.delayed` Para esperar un tiempo. ```dart await Future.delayed(Duration(seconds: 2)); print('2 segundos después'); ``` ### `Future.wait` Para ejecutar múltiples futuros en paralelo y esperar a que *todos* terminen. ```dart void loadDashboard() async { // Inicia ambas peticiones simultáneamente var profileFuture = getProfile(); var newsFuture = getNews(); // Espera a ambas var results = await Future.wait([profileFuture, newsFuture]); var profile = results[0]; var news = results[1]; } ``` ## FutureBuilder en Flutter Widget para construir UI basada en un Future. ```dart class MyPage extends StatelessWidget { // Importante: Guarda el future en una variable de estado // No llames a la API directamente en el build() final Future _dataFuture = fetchData(); @override Widget build(BuildContext context) { return FutureBuilder( future: _dataFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return CircularProgressIndicator(); } if (snapshot.hasError) { return Text('Error: ${snapshot.error}'); } return Text('Data: ${snapshot.data}'); }, ); } } ``` ## Errores Comunes ### 1. Olvidar `await` ```dart void main() { print('Inicio'); saveData(); // ❌ Se ejecuta "fire and forget" print('Fin'); // Se imprime antes de que saveData termine } ``` ### 2. `async` en `forEach` El `forEach` no espera futuros. ```dart // ❌ Malo: No espera users.forEach((user) async { await saveUser(user); }); print('Done'); // Se imprime antes de guardar // ✅ Bueno: Usa for-in for (final user in users) { await saveUser(user); } print('Done'); ``` ## Conclusión - Usa `async/await` para código asíncrono legible. - Usa `Future.wait` para paralelismo. - Maneja errores con `try-catch`. - Usa `FutureBuilder` para mostrar estados de carga en Flutter.

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.