Diferencia entre revisiones de «Flutter DART Programación asíncrona»
Ir a la navegación
Ir a la búsqueda
Se puede ver como 'datos' no vale la lista de imágenes
| Línea 223: | Línea 223: | ||
===Ejercicios propuestos=== | ===Ejercicios propuestos=== | ||
| − | '''Ejercicio 1: | + | '''Ejercicio 1:''' Sabrías aplicar los conceptos aprendidos para que el pedido apareza correctamente ([https://dart.dev/codelabs/async-await ejercicio obtenido de este enlace]): |
:<syntaxhighlight lang="java" enclose="div" highlight="" > | :<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
String createOrderMessage() { | String createOrderMessage() { | ||
| Línea 243: | Línea 243: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| + | |||
| + | |||
| + | '''Ejercicio 2:''' Se necesita mostrar cual es el premio que recibe un alumno en base a la edad que tenga. | ||
| + | : Crea un método obtenerEdad al que se le envíe un nombre y busque en un mapa, la edad que se corresponde con dicho nombre. Si el nombre no existe en el mapa, debe devolver el valor 0. | ||
| + | : Crea un método de nombre obtenerPremio al que se le envia una edad y devuelve en base a una lista, el premio que le corresponde a esa edad. Utiliza el operador 'resto' para dividir la edad entre el número de regalos y que siempre devuelve un número dentro del rango de la lista. | ||
| + | |||
| + | : Desde la función main, llama a obtenerEdad y el resultado empléalo para llamar a obtenerPremio y muestra el premio. | ||
| + | |||
| + | |||
| + | |||
| + | :<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
| + | int obtenerEdad(String nombre){ | ||
| + | |||
| + | // ACCEDEMOS A INTERNET A BUSCAR LA EDAD | ||
| + | final alumnos = {'pedro' : 27, 'ana' : 35, 'luisa' : 22}; | ||
| + | |||
| + | if (!alumnos.containsKey(nombre)) return 0; | ||
| + | |||
| + | return alumnos[nombre]!; | ||
| + | } | ||
| + | |||
| + | String obtenerPremio(int edad){ | ||
| + | |||
| + | // ACCEDEMOS A INTERNET A BUSCAR LOS PREMIOS | ||
| + | final premios = ['Jamón', 'Coche','Piso']; | ||
| + | |||
| + | return premios[edad%3]; | ||
| + | |||
| + | } | ||
| + | |||
| + | void main() { | ||
| + | |||
| + | int edad = obtenerEdad('pedro'); | ||
| + | String premio = obtenerPremio(edad); | ||
| + | |||
| + | print('Pedro con la edad de $edad, tiene de premio:$premio'); | ||
| + | |||
| + | |||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | |||
| + | * Ahora supón que los dos métodos acceden a Internet y son ejecutados en un hilo separado. Haz lo necesario para que todo siga funcionando igual. | ||
| + | : Haz que el método obtenerEdad tarde 5 segundos en ejecutarse y que el método obtenerPremio tarde 2 segundos. | ||
| + | :<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
| + | </syntaxhighlight> | ||
| + | |||
Revisión del 15:38 12 jul 2021
Sumario
Introducción
- Más información: https://dart.dev/codelabs/async-await
- La programación asíncrona hace referencia al uso de threads para ejecutar en modo 'paralelo' al hilo principal otra serie de tareas.
Futures
- Más información:
void main() { print('Inicia programa'); getImagenes('imagenes/animales').then( (datos) => print(datos) ); print('Fin programa'); } Future<List<String>> getImagenes(String path){ List<String> datos = ['1.jpg','2.jpg','3.jpg','4.jpg']; return Future.delayed(Duration(seconds: 4),() => datos); // Paramos el hilo durante 4 segundos // return Future.value(datos); }
Gestión de errores
void main() { print('Inicia programa'); try { getImages('imagenes/animales').then((datos) { datos.forEach((elem) => print('Dato:$elem')); }).catchError((e) { print(e);} ); } catch(e){ print('Excep:$e'); } print('Fin programa'); } Future<List<String>> getImages(String path){ List<String> imagenes = ['1.jpg','2.jpg','3.jpg']; // Búsqueda de imágenes a partir del path //throw('Exepción no controlada'); return Future.delayed(Duration(seconds: 3),() => Future.error('Error controlado')); }
Estado Completo
- Un Future puede tener dos estados:
- Incompleto: Cuando se está ejecutando.
- Completo: Cuando ha terminado de ejecutarse. Este estado lo va a alcanzar haya o no error durante la ejecución del Future.
- Es decir, el método then se va a ejecutar sólo cuando el Future acabe de ejecutarse correctamente mientras que el método whenComplete se ejecuta tanto si ha ido bien como si ha habido un error.
- Veamos un ejemplo:
void main() { print('Inicia programa'); cargarImagenes().then((datos) => print('Acabó el Future1 sin errores')). whenComplete(() => print('Terminó Future1')); cargarImagenesConError(). then((datos) => print('Acabó el Future2 sin errores')). catchError((e) { print('Capturando el error:$e'); }). whenComplete(() => print('Terminó Future2')); print('Fin programa'); } Future<void> cargarImagenesConError(){ return Future.delayed(Duration(seconds: 2),() => throw('Error cargando imágenes')); } Future<void> cargarImagenes(){ return Future.delayed(Duration(seconds: 2),() { print('Cargamos imágenes');}); }
- El Future cargarImagenes no devuelva nada (void) y se ejecuta sin errores, por lo tanto, la llamada a la función desde el hilo principal ejecuta el método then y el método whenComplete.
- El Future cargarImagenesConError no devuelva nada (void) y se ejecuta con errores, por lo tanto, la llamada a la función desde el hilo principal ejecuta el método catchError y el método whenComplete.
Async/Await
- Más información:
- En los ejemplos anteriores vimos que para llamar a un Future y obtener el resultado disponemos del método then.
- Pero existe otra forma de obtener el resultado de la llamada a un Future que es:
void main() { print('Inicia programa'); final datos = getImages('imagenes/animales'); print('Los datos son:$datos'); print('Fin programa'); } Future<List<String>> getImages(String path) { List<String> imagenes = ['1.jpg','2.jpg','3.jpg']; // Búsqueda de imágenes a partir del path return Future.delayed(Duration(seconds: 3),() => imagenes); }
- El problema que tiene esta forma de obtener el resultado de un Future, es que, al ejecutarse en otro hilo separado, datos puede que no tenga el resultado cuando llegue a la línea donde se imprimen dichos datos:
- Para solucionar el problema podemos pensar en usar el 'método then', ya que éste sólo se llama cuando el Future devuelve los datos, pero entonces estaríamos obligados a tener toda la lógica del programa que tenga que ver con los datos recibidos, dentro del then como vimos en los ejemplos anteriores...
void main() { print('Inicia programa'); List<String>? datos; getImages('imagenes/animales').then((datos) { print(datos); }); print('Fin programa'); }
- Por lo tanto, en algunos casos puede ser necesario que el hilo principal 'espere' hasta que el Future devueva el resultado.
- Para lograr esto debemos:
- Llamar al future con la palabra clave await antes del nombre de la función.
- Definir la función desde donde se está llamando como async.
void main() async { // Definimos como async ya que va a hacer una llamada con await a un Future print('Inicia programa'); final datos = await getImages('imagenes/animales'); // Esperamos a que termine de ejecutarse. print('Datos obtenidos después de ejecutar el Future:$datos'); print('Fin programa'); } Future<List<String>> getImages(String path) { List<String> imagenes = ['1.jpg','2.jpg','3.jpg']; // Búsqueda de imágenes a partir del path return Future.delayed(Duration(seconds: 3),() => imagenes); }
Ejercicios propuestos
Ejercicio 1: Sabrías aplicar los conceptos aprendidos para que el pedido apareza correctamente (ejercicio obtenido de este enlace):
String createOrderMessage() { var order = fetchUserOrder(); return 'Tu pedido es: $order'; } Future<String> fetchUserOrder() => // Imagine that this function is // more complex and slow. Future.delayed( const Duration(seconds: 2), () => 'Café largo', ); void main() { print('Preparando el pedido...'); print(createOrderMessage()); }
Ejercicio 2: Se necesita mostrar cual es el premio que recibe un alumno en base a la edad que tenga.
- Crea un método obtenerEdad al que se le envíe un nombre y busque en un mapa, la edad que se corresponde con dicho nombre. Si el nombre no existe en el mapa, debe devolver el valor 0.
- Crea un método de nombre obtenerPremio al que se le envia una edad y devuelve en base a una lista, el premio que le corresponde a esa edad. Utiliza el operador 'resto' para dividir la edad entre el número de regalos y que siempre devuelve un número dentro del rango de la lista.
- Desde la función main, llama a obtenerEdad y el resultado empléalo para llamar a obtenerPremio y muestra el premio.
int obtenerEdad(String nombre){ // ACCEDEMOS A INTERNET A BUSCAR LA EDAD final alumnos = {'pedro' : 27, 'ana' : 35, 'luisa' : 22}; if (!alumnos.containsKey(nombre)) return 0; return alumnos[nombre]!; } String obtenerPremio(int edad){ // ACCEDEMOS A INTERNET A BUSCAR LOS PREMIOS final premios = ['Jamón', 'Coche','Piso']; return premios[edad%3]; } void main() { int edad = obtenerEdad('pedro'); String premio = obtenerPremio(edad); print('Pedro con la edad de $edad, tiene de premio:$premio'); }
- Ahora supón que los dos métodos acceden a Internet y son ejecutados en un hilo separado. Haz lo necesario para que todo siga funcionando igual.
- Haz que el método obtenerEdad tarde 5 segundos en ejecutarse y que el método obtenerPremio tarde 2 segundos.
Enlace a la página principal de la UD2
Enlace a la página principal del curso
-- Ángel D. Fernández González -- (2021).