Futures y async/await
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 76 de 110.
En las aplicaciones reales, muchas operaciones toman tiempo: obtener datos de un servidor, leer archivos o esperar la entrada del usuario. Dart maneja esto con Future, que representa un valor que estará disponible en algún momento en el futuro.
Un Future es como una promesa: "Te daré el resultado cuando esté listo". Puedes crear uno usando Future.delayed() para simular una operación que toma tiempo:
Future<String> fetchUserName() {
return Future.delayed(
Duration(seconds: 1),
() => 'Alice',
);
}Para trabajar con el resultado de un Future, utiliza async y await. Marca tu función como async, luego utiliza await para pausar la ejecución hasta que el Future se complete:
Future<void> main() async {
print('Fetching user...');
String name = await fetchUserName();
print('Hello, $name!');
}
Future<String> fetchUserName() {
return Future.delayed(
Duration(seconds: 1),
() => 'Alice',
);
}Sin await, obtendrías un Future<String> en lugar de la cadena real. La palabra clave await desenvuelve el Future y te da el valor que contiene. Ten en cuenta que cualquier función que use await debe estar marcada como async, y automáticamente devuelve un Future.
También puedes devolver valores directamente desde funciones async - Dart los envuelve en un Future automáticamente:
Future<int> calculateTotal() async {
var a = await fetchNumber();
var b = await fetchNumber();
return a + b; // Envuelto automáticamente en Future<int>
}Desafío
Fácil¡Vamos a crear un servicio meteorológico que simule la obtención de datos climáticos de diferentes ciudades! Practicarás el uso de Future, async y await para manejar operaciones que tardan tiempo en completarse.
Organizarás tu código en dos archivos:
weather_service.dart: Crea una claseWeatherServiceque simule la obtención de información meteorológica. Tu clase debe tener:- Un método
fetchTemperature(String city)que devuelva unFuture<int>. UsaFuture.delayed()con una duración de 100 milisegundos para simular el retraso de la red. El método debe devolver una temperatura basada en el nombre de la ciudad: devuelve la longitud del nombre de la ciudad multiplicada por 3. - Un método
fetchCondition(String city)que devuelva unFuture<String>. UsaFuture.delayed()con un retraso de 100 milisegundos. Devuelve'Sunny'si el nombre de la ciudad tiene un número par de caracteres, de lo contrario devuelve'Cloudy'. - Un método asíncrono
getFullReport(String city)que devuelva unFuture<String>. Este método debe esperar (await) tanto afetchTemperaturecomo afetchCondition, y luego devolver una cadena formateada:'[city]: [temperature]C, [condition]'
- Un método
main.dart: Importa tu servicio meteorológico y demuestra cómo funcionan las operaciones asíncronas. Tu función main debe ser asíncrona y:- Crear una instancia de
WeatherService - Imprimir
Fetching weather data... - Esperar (await) e imprimir el informe completo para
'Paris' - Esperar (await) e imprimir el informe completo para
'Tokyo' - Esperar (await) e imprimir el informe completo para
'London' - Imprimir
Done!
- Crear una instancia de
Observa cómo cada llamada a getFullReport espera a que se obtengan tanto la temperatura como la condición antes de devolver el resultado combinado. ¡La palabra clave await pausa la ejecución hasta que cada Future se completa!
Salida esperada:
Fetching weather data...
Paris: 15C, Cloudy
Tokyo: 15C, Cloudy
London: 18C, Sunny
Done!Hoja de referencia
Un Future representa un valor que estará disponible en el futuro. Se utiliza para operaciones que toman tiempo, como obtener datos o leer archivos.
Crea un Future usando Future.delayed():
Future<String> fetchUserName() {
return Future.delayed(
Duration(seconds: 1),
() => 'Alice',
);
}Usa async y await para trabajar con Futures. Marca la función como async y usa await para pausar la ejecución hasta que el Future se complete:
Future<void> main() async {
print('Fetching user...');
String name = await fetchUserName();
print('Hello, $name!');
}La palabra clave await desempaqueta el Future y te da el valor real. Sin ella, obtendrías un Future<String> en lugar de la cadena.
Cualquier función que use await debe estar marcada como async y devuelve automáticamente un Future.
Los valores de retorno de las funciones async se envuelven automáticamente en un Future:
Future<int> calculateTotal() async {
var a = await fetchNumber();
var b = await fetchNumber();
return a + b; // Envuelto automáticamente en Future<int>
}Pruébalo tú mismo
import 'weather_service.dart';
Future<void> main() async {
// TODO: Crea una instancia de WeatherService
// TODO: Imprime 'Fetching weather data...'
// TODO: Espera e imprime el informe completo para 'Paris'
// TODO: Espera e imprime el informe completo para 'Tokyo'
// TODO: Espera e imprime el informe completo para 'London'
// TODO: Imprime 'Done!'
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de POO
Archivos externosLibrerías e importacionesIntroducción a la POOClases vs. ObjetosLa palabra clave thisMétodosVariables de instanciaConceptos básicos de constructoresResumen - Calculadora sencilla4Seguridad de nulos
Introducción a la seguridad de nulosNulables vs No nulablesLos operadores ? y !Palabra clave Late y Null SafetyOperadores Null-awareNull Safety en clasesResumen - Sistema de perfil de usuario7Clases abstractas e interfaces
Clases abstractasMétodos abstractosInterfaces en DartInterfaces implícitasImplementar vs. ExtenderInterfaces múltiplesRepaso - Calculadora de figuras10Colecciones y Genéricos
Visión general de List, Set y MapColecciones con seguridad de tiposClases genéricasMétodos genéricosRestricciones genéricasIterable e IteratorResumen - Almacenamiento genérico2Constructores en Dart
Constructor por defectoConstructores nombradosListas de inicializaciónConstructores constantesConstructores de fábricaConstructores de redireccionamientoResumen - Constructor de formas5Encapsulamiento
Miembros públicos vs. privadosLa convención del prefijo _Privacidad a nivel de libreríaProfundidad en Getters y SettersOcultamiento de informaciónResumen - Registros de estudiantes8Mixins
Introducción a los MixinsCreación de MixinsUso de múltiples MixinsPalabra clave on en MixinsMixin vs HerenciaMixin vs InterfazResumen - Sistema Animal11Métodos especiales
Sobrescritura de toString()Sobrescritura de hashCode y ==Interfaz ComparableMétodo call()Sobrescritura de noSuchMethodResumen - Colección personalizada14Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy3Propiedades de clase
Miembros de instancia vs. estáticosCampos Final y ConstVariables LateMétodos y campos estáticosGetters y SettersResumen - Gestor de cuentas bancarias6Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosLa anotación @overrideLa palabra clave final en clasesConstructores y herenciaResumen - Jerarquía de empleados9Polimorfismo
Fundamentos del polimorfismoPolimorfismo mediante interfacesComprobación de tipos en tiempo de ejecuciónLos operadores is y asPalabra clave covariantResumen - Procesador de pagos12POO Asíncrona
Futures y async/awaitFundamentos de StreamsStream ControllersConstructores asíncronosAsincronía en métodos de claseRepaso - Data Fetcher15Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository