Dados los ejemplos de código a continuación, ¿hay alguna diferencia en el comportamiento y, de ser así, cuáles son esas diferencias?
return await promise
async function delay1Second() {
return (await delay(1000));
}
return promise
async function delay1Second() {
return delay(1000);
}
Según tengo entendido, el primero tendría manejo de errores dentro de la función asíncrona, y los errores saldrían de la Promesa de la función asíncrona. Sin embargo, el segundo requeriría un tic menos. ¿Es esto correcto?
Este fragmento es solo una función común para devolver una Promesa como referencia.
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
javascript
async-await
PitaJ
fuente
fuente
async
de tu segundo (return promise
) ejemplo.promise.then(() => nestedPromise)
aplanaría y "seguiría" elnestedPromise
. Es interesante cómo es diferente de las tareas anidadas en C # donde tendríamos queUnwrap
hacerlo. En una nota al margen, parece que lasawait somePromise
llamadasPromise.resolve(somePromise).then
, en lugar de solosomePromise.then
, tienen algunas diferencias semánticas interesantes.Respuestas:
La mayoría de las veces, no hay una diferencia observable entre
return
yreturn await
. Ambas versiones dedelay1Second
tienen exactamente el mismo comportamiento observable (pero dependiendo de la implementación, lareturn await
versión podría usar un poco más de memoria porquePromise
podría crearse un objeto intermedio ).Sin embargo, como señaló @PitaJ, hay un caso en el que hay una diferencia: si
return
oreturn await
está anidado en un bloquetry
-catch
. Considere este ejemploEn la primera versión, la función async espera la promesa rechazada antes de devolver su resultado, lo que provoca que el rechazo se convierta en una excepción y
catch
se alcance la cláusula; la función devolverá así una promesa que se resuelve en la cadena "¡Guardado!".La segunda versión de la función, sin embargo, devuelve la promesa rechazada directamente sin esperarla dentro de la función asíncrona , lo que significa que no se llama al
catch
caso y la persona que llama obtiene el rechazo.fuente
return new Promise(function(resolve, reject) { })
dentro de unfor...of
bucle y luego llamarresolve()
dentro del bucle después depipe()
que no pausa la ejecución del programa hasta que la tubería se haya completado, como se desea, sin embargo, el usoawait new Promise(...)
sí lo hace. ¿Es esta última incluso una sintaxis válida / correcta? es 'taquigrafía' parareturn await new Promise(...)
? ¿Podrías ayudarme a entender por qué funciona el último y el primero no? para el contexto, el escenario es en elsolution 02
de esta respuestaComo se mencionó en otras respuestas, es probable que exista un ligero beneficio en el rendimiento al dejar que la promesa brote devolviéndola directamente, simplemente porque no tiene que esperar el resultado primero y luego envolverlo con otra promesa nuevamente. Sin embargo, nadie ha hablado todavía sobre la optimización de llamadas finales .
La optimización de llamadas de cola , o "llamadas de cola adecuadas" , es una técnica que utiliza el intérprete para optimizar la pila de llamadas. Actualmente, todavía no hay muchos tiempos de ejecución que lo admitan, aunque técnicamente es parte del estándar ES6 , pero es posible que se agregue soporte en el futuro, por lo que puede prepararse para eso escribiendo un buen código en el presente.
En pocas palabras, TCO (o PTC) optimiza la pila de llamadas al no abrir un nuevo marco para una función que es devuelta directamente por otra función. En cambio, reutiliza el mismo marco.
Dado que
delay()
es devuelto directamente pordelay1Second()
, los tiempos de ejecución que admiten PTC primero abrirán un marco paradelay1Second()
(la función externa), pero luego, en lugar de abrir otro marco paradelay()
(la función interna), simplemente reutilizará el mismo marco que se abrió para la función externa. Esto optimiza la pila ya que puede evitar un desbordamiento de pila (hehe) con muy grandes funciones recursivas, por ejemplo,fibonacci(5e+25)
. Básicamente, se convierte en un bucle, que es mucho más rápido.PTC solo se habilita cuando la función interna se devuelve directamente . No se usa cuando el resultado de la función se modifica antes de que se devuelva, por ejemplo, si tenía
return (delay(1000) || null)
, oreturn await delay(1000)
.Pero como dije, la mayoría de los tiempos de ejecución y los navegadores aún no son compatibles con PTC, por lo que probablemente no haga una gran diferencia ahora, pero no estaría de más preparar su código para el futuro.
Lea más en esta pregunta: Node.js: ¿Hay optimizaciones para llamadas finales en funciones asíncronas?
fuente
Esta es una pregunta difícil de responder, porque depende en la práctica de cómo su transpiler (probablemente
babel
) se procese realmenteasync/await
. Las cosas que están claras independientemente:Ambas implementaciones deben comportarse igual, aunque la primera implementación puede tener una menos
Promise
en la cadena.Especialmente si descarta lo innecesario
await
, la segunda versión no requeriría ningún código adicional del transpilador, mientras que la primera sí.Por lo tanto, desde una perspectiva de depuración y rendimiento del código, la segunda versión es preferible, aunque solo un poco, mientras que la primera versión tiene un ligero beneficio de legibilidad, ya que indica claramente que devuelve una promesa.
fuente
undefined
) y el segundo devuelve unPromise
.async/await
, me resulta mucho más difícil razonar. @PitaJ es correcto, ambas funciones devuelven una Promesa.try-catch
? En elreturn promise
caso, cualquierarejection
no sería capturado, ¿correcto, mientras que, en elreturn await promise
caso, sería correcto?await
cada uno de estos en algún sitio de llamada, el resultado será muy diferente.aqui te dejo un codigo practico para que puedas entenderlo la diferencia
la función "x" solo es una función asíncrona que tiene otras funciones si se borrará el retorno imprime "más código ..."
la variable x es solo una función asincrónica que a su vez tiene otra función asincrónica, en la principal del código invocamos una espera para llamar a la función de la variable x, cuando se completa sigue la secuencia del código, eso sería normal para "async / await", pero dentro de la función x hay otra función asincrónica, y esta devuelve una promesa o devuelve una "promesa" permanecerá dentro de la función x, olvidando el código principal, es decir, no imprimirá el "console.log (" más código .. "), en cambio si ponemos" await "esperará cada función que se complete y finalmente siga la secuencia normal del código principal.
debajo de "console.log (" terminado 1 "elimina el" retorno ", verás el comportamiento.
fuente
Aquí hay un ejemplo mecanografiado que puede ejecutar y convencerse de que necesita ese "retorno en espera"
fuente
Diferencia notable: el rechazo de promesas se maneja en diferentes lugares
return somePromise
pasará somePromise al sitio de la llamada yawait
somePromise para asentarse en el sitio de la llamada (si hay alguno). Por lo tanto, si se rechaza somePromise, no será manejado por el bloque de captura local, sino por el bloque de captura del sitio de llamada.return await somePromise
Primero esperará alguna promesa de establecerse localmente. Por lo tanto, el valor o la excepción primero se manejarán localmente. => El bloque de captura local se ejecutará sisomePromise
se rechaza.Razón:
return await Promise
espera tanto localmente como afuera,return Promise
espera solo afueraPasos detallados:
promesa de devolución
delay1Second()
;delay1Second()
, la funcióndelay(1000)
devuelve una promesa inmediatamente con[[PromiseStatus]]: 'pending
. Vamos a llamarlodelayPromise
.Promise.resolve()
( Fuente ). Comodelay1Second
es una función asíncrona, tenemos:Promise.resolve(delayPromise)
regresadelayPromise
sin hacer nada porque la entrada ya es una promesa (ver MDN Promise.resolve ):await
espera hasta quedelayPromise
se resuelva.delayPromise
se cumple con PromiseValue = 1:delayPromise
es rechazado:regreso a la espera de la promesa
delay1Second()
;delay1Second()
, la funcióndelay(1000)
devuelve una promesa inmediatamente con[[PromiseStatus]]: 'pending
. Vamos a llamarlodelayPromise
.delayPromise
se establezca.delayPromise
se cumple con PromiseValue = 1:delayPromise
se rechaza:Glosario:
Promise.[[PromiseStatus]]
cambios depending
aresolved
orejected
fuente