# 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.