Diferencia entre revisiones de «Flutter DART Programación asíncrona»

De MediaWiki
Ir a la navegación Ir a la búsqueda
Línea 220: Línea 220:
  
  
 +
 +
===Ejercicios propuestos===
 +
 +
'''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="" >
 +
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());
 +
}
 +
</syntaxhighlight>
  
  

Revisión del 15:20 12 jul 2021

Introducción

  • 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:
Flutter dart async 1.JPG
Se puede ver como 'datos' no vale la lista de imágenes
  • 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());
}





Enlace a la página principal de la UD2

Enlace a la página principal del curso




-- Ángel D. Fernández González -- (2021).