informatica:programacion:cursos:programacion_avanzada_javascript:funciones_asincronas
Diferencias
Muestra las diferencias entre dos versiones de la página.
| Ambos lados, revisión anteriorRevisión previaPróxima revisión | Revisión previa | ||
| informatica:programacion:cursos:programacion_avanzada_javascript:funciones_asincronas [2024/10/16 08:58] – [Introducción] tempwin | informatica:programacion:cursos:programacion_avanzada_javascript:funciones_asincronas [2024/10/30 12:58] (actual) – [Ejercicio propuesto] tempwin | ||
|---|---|---|---|
| Línea 17: | Línea 17: | ||
| ===== ¿Qué son las funciones asíncronas? | ===== ¿Qué son las funciones asíncronas? | ||
| + | Una función asíncrona es aquélla que **se ejecuta asíncronamente y que utiliza implícitamente una //promise// para devolver su valor**. Las funciones asíncronas se definen exactamente igual que las funciones normales **salvo que usamos la palabra clave '' | ||
| + | |||
| + | <code javascript> | ||
| + | async function answerAsync() { | ||
| + | console.log(' | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Dado que las funciones asíncronas son también simples funciones, aplicar '' | ||
| + | |||
| + | Las funciones asíncronas se invocan exactamente igual que las funciones tradicionales. Es decir, la función anterior la podemos invocar usando simplemente '' | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Si nos fijamos en la imagen anterior, observamos cómo al invocar la función '' | ||
| + | |||
| + | Esto nos permite, por supuesto, aplicar todo lo que conocemos de // | ||
| + | |||
| + | <code javascript> | ||
| + | answerAsync().then(() => console.log(' | ||
| + | </ | ||
| + | |||
| + | En este caso, una vez la función asíncrona se ha ejecutado, se ejecuta la función indicada dentro del '' | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Por lo tanto toda función '' | ||
| + | |||
| + | En nuestro ejemplo '' | ||
| + | |||
| + | <code javascript> | ||
| + | async function answerAsync() { | ||
| + | return 42; | ||
| + | } | ||
| + | |||
| + | answerAsync().then(v => console.log(" | ||
| + | </ | ||
| + | |||
| + | Este código imprime '' | ||
| + | |||
| + | <WRAP center round tip 60%> | ||
| + | **Recuerda**: | ||
| + | </ | ||
| ===== Esperas asíncronas ===== | ===== Esperas asíncronas ===== | ||
| + | El ejemplo que hemos visto no es muy representativo porque, a pesar de que hemos creado una función asíncrona (con '' | ||
| + | |||
| + | Si trasladamos el ejemplo anterior a // | ||
| + | |||
| + | <code javascript> | ||
| + | function answerAsync() { | ||
| + | const pr = new Promise((resolve, | ||
| + | console.log(' | ||
| + | resolve() | ||
| + | }); | ||
| + | | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Quizá ahora se observa mejor cómo la función '' | ||
| + | |||
| + | Lo interesante de las funciones asíncronas es que **pueden realizar esperas asíncronas**: | ||
| + | |||
| + | ¿Y qué es lo que podemos esperar asíncronamente? | ||
| + | |||
| + | * La resolución de una //promise// | ||
| + | * Dado que las funciones asíncronas devuelven una promise, podemos esperar asíncronamente la finalización de una función asíncrona | ||
| + | |||
| + | Para esperas asíncronas usamos la palabra clave '' | ||
| ===== DEMO: De promise a async ===== | ===== DEMO: De promise a async ===== | ||
| + | Veamos la relación entre '' | ||
| + | |||
| + | Partamos de la siguiente función que devolverá una //promise// que se resolverá al cabo de los segundos que pasemos por parámetro: | ||
| + | |||
| + | <code javascript> | ||
| + | function waitPromise(sec) { | ||
| + | const pr = new Promise((res, | ||
| + | window.setTimeout(res, | ||
| + | }); | ||
| + | | ||
| + | return pr; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Probamos: | ||
| + | |||
| + | <code javascript> | ||
| + | console.log(" | ||
| + | |||
| + | waitPromise(3).then(() => { | ||
| + | console.log(" | ||
| + | }); | ||
| + | |||
| + | console.log(" | ||
| + | </ | ||
| + | |||
| + | Ahora haremos lo mismo usando '' | ||
| + | |||
| + | <code javascript> | ||
| + | console.log(" | ||
| + | |||
| + | async function waitAsync() { | ||
| + | console.log(" | ||
| + | await waitPromise(3); | ||
| + | console.log(" | ||
| + | } | ||
| + | |||
| + | waitAsync(); | ||
| + | |||
| + | console.log(" | ||
| + | </ | ||
| + | |||
| + | <WRAP center round important 60%> | ||
| + | '' | ||
| + | </ | ||
| + | |||
| + | La salida por consola será: | ||
| + | |||
| + | < | ||
| + | Inicio espera | ||
| + | dentro de waitAsync, pero antes del await | ||
| + | fin | ||
| + | espera terminada | ||
| + | </ | ||
| ===== Un " | ===== Un " | ||
| + | Vamos a ver un ejemplo: crearemos una función que cargue asíncronamente una página web y que nos devuelva el tiempo (en milisegundos) que ha tardado. Una especie de " | ||
| + | |||
| + | Observa que se trata de una función normal y corriente que devuelve una // | ||
| + | |||
| + | <code javascript> | ||
| + | function ping(url) { | ||
| + | const pr = new Promise((resolve, | ||
| + | const req = new XMLHttpRequest(); | ||
| + | const init = performance.now(); | ||
| + | req.open(' | ||
| + | req.onreadystatechange = function(){ | ||
| + | if (req.readyState == XMLHttpRequest.DONE) { | ||
| + | if (req.status == 200) { | ||
| + | const end = performance.now(); | ||
| + | resolve(end-init); | ||
| + | } | ||
| + | else { | ||
| + | reject(-1); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | req.send(); | ||
| + | }) | ||
| + | return pr; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Nota: observa el uso de '' | ||
| + | |||
| + | Por supuesto, dado que dicha función devuelve una //promise// podemos usar '' | ||
| + | |||
| + | <code javascript> | ||
| + | ping(' | ||
| + | .then(r => console.log(`ha tardado ${r}`)) | ||
| + | .catch(() => console.log(' | ||
| + | </ | ||
| + | |||
| + | Hasta este punto no hemos visto nada nuevo. **Ahora vamos a introducir una espera asíncrona**, | ||
| + | |||
| + | <code javascript> | ||
| + | const test = async() => { | ||
| + | let ms = await ping(' | ||
| + | console.log(" | ||
| + | } | ||
| + | |||
| + | test(); | ||
| + | </ | ||
| + | |||
| + | Fíjate en un par de cuestiones importantes: | ||
| + | |||
| + | * El uso de '' | ||
| + | * **Para usar '' | ||
| + | |||
| + | Y recuerda: el hecho de que '' | ||
| + | |||
| + | <code javascript> | ||
| + | const test = async(uri) => { | ||
| + | let ms = await ping(uri); | ||
| + | console.log(" | ||
| + | } | ||
| + | |||
| + | const testm = async() => { | ||
| + | await test(' | ||
| + | await test(' | ||
| + | } | ||
| + | |||
| + | testm(); | ||
| + | </ | ||
| + | |||
| + | Por supuesto, para que la función '' | ||
| + | |||
| + | Observa cómo **el uso de '' | ||
| ===== DEMO: Más sobre async y promises ===== | ===== DEMO: Más sobre async y promises ===== | ||
| + | Vamos a realizar un experimento que consiste en capturar el resultado de la función devuelta por '' | ||
| + | |||
| + | <code javascript> | ||
| + | function waitPromise(sec) { | ||
| + | const pr = new Promise((res, | ||
| + | window.setTimeout(res, | ||
| + | }); | ||
| + | |||
| + | return pr; | ||
| + | } | ||
| + | |||
| + | console.log(" | ||
| + | |||
| + | async function waitAsync() { | ||
| + | console.log(" | ||
| + | await waitPromise(3); | ||
| + | console.log(" | ||
| + | } | ||
| + | |||
| + | let resultado = waitAsync(); | ||
| + | console.log(" | ||
| + | </ | ||
| + | |||
| + | Si '' | ||
| + | |||
| + | Por eso podemos escribir: | ||
| + | |||
| + | <code javascript> | ||
| + | let resultado = waitAsync(); | ||
| + | |||
| + | resultado.then(() => { | ||
| + | console.log(" | ||
| + | }); | ||
| + | </ | ||
| + | |||
| + | Pongamos ahora el ejemplo de que la promesa devuelve un valor: | ||
| + | |||
| + | <code javascript> | ||
| + | async function waitAsync() { | ||
| + | console.log(" | ||
| + | await waitPromise(3); | ||
| + | console.log(" | ||
| + | return 42; | ||
| + | } | ||
| + | |||
| + | let resultado = waitAsync(); | ||
| + | |||
| + | resultado.then((v) => { | ||
| + | console.log(" | ||
| + | }); | ||
| + | </ | ||
| + | |||
| + | Lo que hicimos con el '' | ||
| + | |||
| + | <code javascript> | ||
| + | async function f2() { | ||
| + | let resultado = await waitAsync(); | ||
| + | console.log(" | ||
| + | } | ||
| + | |||
| + | f2(); // -> ' | ||
| + | </ | ||
| + | |||
| + | '' | ||
| + | |||
| + | Recapitulado: | ||
| + | |||
| + | * '' | ||
| + | * Para utilizar '' | ||
| + | * Las funciones marcadas con '' | ||
| + | * Cuando una función asíncrona devuelve un resultado, '' | ||
| ===== Errores en funciones asíncronas ===== | ===== Errores en funciones asíncronas ===== | ||
| + | Una de las facilidades de usar '' | ||
| + | |||
| + | <code javascript> | ||
| + | function asyncPromise() { | ||
| + | return new Promise((resolve, | ||
| + | reject(" | ||
| + | }); | ||
| + | } | ||
| + | |||
| + | try { | ||
| + | asyncPromise().then(() => { | ||
| + | console.log(' | ||
| + | }); | ||
| + | } | ||
| + | catch (error) { | ||
| + | console.err(' | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | **Usando '' | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | La imagen muestra el resultado de ejecutar dicho código; en Firefox a la izquierda y en Chrome a la derecha. Observa cómo el '' | ||
| + | |||
| + | Como ya sabemos, para capturar errores en // | ||
| + | |||
| + | Recuerda además, que dentro de una //promise// lanzar un error, rechaza la // | ||
| + | |||
| + | <code javascript> | ||
| + | function asyncPromise() { | ||
| + | return new Promise((resolve, | ||
| + | throw (" | ||
| + | }); | ||
| + | } | ||
| + | |||
| + | try { | ||
| + | asyncPromise().then(() => { | ||
| + | console.log(' | ||
| + | }); | ||
| + | } | ||
| + | catch (error) { | ||
| + | console.error(' | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Ahora, a pesar de usar '' | ||
| + | |||
| + | ==== Bloques try/catch y async/await ==== | ||
| + | |||
| + | El uso de '' | ||
| + | |||
| + | <code javascript> | ||
| + | function asyncPromise() { | ||
| + | return new Promise((resolve, | ||
| + | throw (" | ||
| + | }); | ||
| + | } | ||
| + | |||
| + | async function test() { | ||
| + | try { | ||
| + | await asyncPromise(); | ||
| + | console.log(' | ||
| + | } | ||
| + | catch (error) { | ||
| + | console.error(' | ||
| + | } | ||
| + | } | ||
| + | |||
| + | test(); | ||
| + | </ | ||
| + | |||
| + | Observa que **no se ha modificado '' | ||
| + | |||
| + | Por lo tanto, al usar '' | ||
| ===== Esperas asíncronas en paralelo ===== | ===== Esperas asíncronas en paralelo ===== | ||
| + | El siguiente código muestra una función que devuelve una //promise// que se resuelve al cabo de '' | ||
| + | |||
| + | <code javascript> | ||
| + | function timeout(sec) { | ||
| + | return new Promise(resolve => { | ||
| + | setTimeout(() => { resolve(x); | ||
| + | }); | ||
| + | } | ||
| + | |||
| + | ¿Cuánto tiempo tarda en ejecutarse el siguiente código? | ||
| + | |||
| + | async function test() { | ||
| + | await timeout(2); | ||
| + | await timeout(3); | ||
| + | console.log(' | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Piénsalo un poco antes de responder: el código realiza dos esperas asíncronas por la función timeout. Una espera es de 2 segundos y la otra es de 3. ¿Cuánto tiempo estamos esperando? | ||
| + | |||
| + | La respuesta correcta es **cinco**. El primer '' | ||
| + | |||
| + | Es decir, varios '' | ||
| + | |||
| + | Pues la respuesta es que sí, y pasa por tener presente que '' | ||
| + | |||
| + | <code javascript> | ||
| + | async function test() { | ||
| + | await Promise.all([timeout(2), | ||
| + | console.log(' | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Ahora el '' | ||
| ===== Ejercicio propuesto ===== | ===== Ejercicio propuesto ===== | ||
| + | Crea una función que, usando la API '' | ||
| + | |||
| + | <code javascript> | ||
| + | uriSize(' | ||
| + | .then(s => console.log(' | ||
| + | </ | ||
| + | |||
| + | Crea la función asíncrona '' | ||
| + | |||
| + | <code javascript> | ||
| + | getLargestUri([ | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | .then(v => console.log(' | ||
| + | </ | ||
| + | |||
| + | Intenta que la función '' | ||
| + | |||
| + | {{ : | ||
| + | ==== Consejos ==== | ||
| + | |||
| + | En contra de lo que pueda parecer, este es un **ejercicio relativamente complejo**, así que tómatelo con calma y repasa lo necesario del módulo de fetch API. | ||
| + | |||
| + | La función '' | ||
| + | |||
| + | ==== Y un pequeño reto adicional ==== | ||
| + | |||
| + | En la función '' | ||
| + | |||
| + | Crea una función '' | ||
| + | |||
| + | <code javascript> | ||
| + | [{v:42, name:' | ||
| + | </ | ||
| + | |||
| + | (En este caso debe devolver el primer elemento) | ||
| + | Una vez tengas esa función '' | ||
informatica/programacion/cursos/programacion_avanzada_javascript/funciones_asincronas.1729061911.txt.gz · Última modificación: por tempwin
