prmph
He estado jugando con la función en un SPA usando TypeScript y promesas nativas, y noté que incluso si refactorizo una función de ejecución prolongada en una función asíncrona que devuelve una promesa, la interfaz de usuario sigue sin responder.
Entonces mis preguntas son:
-
¿Cómo ayuda exactamente la nueva función async/await a evitar el bloqueo de la interfaz de usuario en el navegador? ¿Hay algún paso adicional especial que uno deba tomar al usar async/await para obtener una interfaz de usuario receptiva?
-
¿Alguien puede crear un violín para demostrar cómo async/await ayuda a que la interfaz de usuario responda?
-
¿Cómo se relaciona async/await con funciones asíncronas anteriores, como setTimeout y XmlHttpRequest?
foque
await p
programa la ejecución del resto de su función cuando promete p
resuelve Eso es todo.
async
te permite usar await
. Eso es (casi) todo lo que hace (también envuelve su resultado en una promesa).
Juntos, hacen que el código sin bloqueo se lea como un código de bloqueo más simple. No desbloquean código.
Para una interfaz de usuario receptiva, descargue el trabajo intensivo de la CPU a un obrero hilo, y pasarle mensajes:
async function brutePrime(n) {
function work({data}) {
while (true) {
let d = 2;
for (; d < data; d++) {
if (data % d == 0) break;
}
if (d == data) return self.postMessage(data);
data++;
}
}
let b = new Blob(["onmessage =" + work.toString()], {type: "text/javascript"});
let worker = new Worker(URL.createObjectURL(b));
worker.postMessage(n);
return await new Promise(resolve => worker.onmessage = e => resolve(e.data));
}
(async () => {
let n = 700000000;
for (let i = 0; i < 10; i++) {
console.log(n = await brutePrime(n + 1));
}
})().catch(e => console.log(e));
-
Puntos para el trabajador sin expediente externo. Ese es un truco genial.
– solarc
19 de julio de 2017 a las 22:44
-
las funciones asíncronas también devuelven una promesa
– código
25 de junio de 2020 a las 16:37
-
“await p programa la ejecución del resto de su función cuando se resuelve la promesa p. Eso es todo”. –> La mejor y más concisa explicación de async/await que he leído en todo Internet.
– rsp1984
20 de marzo de 2022 a las 17:10
async
es una forma más elegante de estructurar el código asíncrono. No permite nuevas capacidades; es solo una sintaxis mejor que las devoluciones de llamada o las promesas.
Entonces, async
no se puede usar para “hacer algo asíncrono”. Si tiene código que tiene que hacer mucho procesamiento basado en CPU, async
no va a hacer mágicamente que la interfaz de usuario responda. Lo que tendrías que hacer es usar algo como trabajadores webcual son la herramienta adecuada para enviar el trabajo vinculado a la CPU a un subproceso en segundo plano para que la interfaz de usuario responda.
-
Supongo que podrías usarlo así, para detener el bloqueo de un bucle. for (let i = 0; i setTimeout(resolución, ms)); }
– Will Voelcker
18 de diciembre de 2017 a las 13:03
-
@ Martian2049: Sí;
async
se basa en Promesas, que no bloquean.– Stephen Cleary
24 de mayo de 2018 a las 15:03
-
“No permite nuevas capacidades” En realidad lo hace. “Entonces, asíncrono no se puede usar para” hacer algo asíncrono “ Pero
await
poder.– un mejor oliver
1 de noviembre de 2018 a las 11:16
-
@abetteroliver: Tal vez estamos viendo diferentes semánticas. Cuando yo digo “[async] no permite nuevas capacidades”, quiero decir que todo lo que puedes hacer con
async
se puede hacer sinasync
usando devoluciones de llamada/promesas, lo cual es trivialmente demostrable porque hasta hace pocoasync
fue una transformación de código en tiempo de compilación sin soporte de tiempo de ejecución.– Stephen Cleary
2 de noviembre de 2018 a las 13:01
-
async
ha estado disponible desde hace bastante tiempo y la transformación a la que te refieres utiliza generadores. Tanto las funciones del generador como las funciones asíncronas preservan la pila y esencialmente permiten pausar las funciones. No puedes lograr eso usando promesas. Tienes razón, por supuesto, esoawait
no hace que una API sea asíncrona, pero debido a la naturaleza asíncrona de las promesas (nativas), otro código puede (!) Tener la oportunidad de ejecutarse antes de que la función continúe.– un mejor oliver
10 dic 2018 a las 20:15
JavaScript es de subproceso único y se ejecuta en el mismo subproceso que la interfaz de usuario. Entonces, todo el código JavaScript bloqueará la interfaz de usuario. Como mencionaron otros trabajadores web, se pueden usar para ejecutar código en otros subprocesos, pero tienen limitaciones.
La diferencia entre las funciones asíncronas y las normales es que devuelven una promesa. Usando una devolución de llamada, puede diferir la ejecución del código, que maneja el resultado de la invocación de una función y, por lo tanto, permite que la interfaz de usuario haga algún trabajo. Los siguientes tres ejemplos tienen el mismo efecto:
async function foo() {
console.log("hi");
return 1;
}
foo().then(result => console.log(result))
console.log("lo");
function foo() {
console.log("hi");
return 1;
}
Promise.resolve(foo()).then(result => console.log(result))
console.log("lo");
function foo() {
console.log("hi");
return 1;
}
const result = foo();
setTimeout(() => console.log(result));
console.log("lo");
En los tres casos, la consola registra hi, lo, 1. Antes de que se imprima 1, la interfaz de usuario puede manejar la entrada del usuario o dibujar actualizaciones. La razón 1 que se imprime en último lugar en los dos primeros casos es que las devoluciones de llamadas para promesas no se ejecutan de inmediato.
await
le permite hacer eso sin devoluciones de llamada:
async function foo() {
console.log("hi");
return 1;
}
async function bar() {
const result = await foo();
console.log(result);
}
bar();
console.log("lo");
Eso también imprimirá hola, lo, 1. Al igual que una devolución de llamada para una promesa, el código después await
nunca se ejecuta inmediatamente.
-
¿Qué pasa si esperas bar() ?
– Rodrigo
25 oct 2018 a las 16:43
-
@Rodrigo Solo puede esperar dentro de las funciones asíncronas.
– un mejor oliver
1 de noviembre de 2018 a las 11:08
-
Por que
hi
imprímete anteslo
?– zzzzzzzz
29 de marzo de 2019 a las 15:18
-
@zzzzzzz
bar
se llama antesconsole.log("lo")
y llamafoo
que llamaconsole.log("hi")
.– un mejor oliver
30 de marzo de 2019 a las 16:14
-
@zzzzzzz Las funciones asíncronas devuelven una promesa.
await
espera a que la promesa sea resuelta o rechazada y eso siempre ocurre de forma asíncrona. No hay tiempo de espera en un sentido estricto, es solo que cualquier código síncrono se ejecuta antes de eso.– un mejor oliver
8 de abril de 2019 a las 17:18
Está claro a partir de la descripción en desarrollador.mozilla.org que no es bloqueante:
La palabra clave await hace que el tiempo de ejecución de JavaScript pause su código en esta línea, permitiendo que otro código se ejecute mientras tanto (Nota: mi negrita), hasta que la llamada a la función asíncrona haya devuelto su resultado. Una vez que se completa, su código continúa ejecutándose a partir de la siguiente línea.
Llego tarde a la fiesta aquí. Quería verificar los casos de uso síncrono y asíncrono.
Para ser claros, async/await no crea código síncrono. solo agrega syntactic sugar
eso hace que el código parezca sincrónico. Debajo de los envoltorios, la lógica Promise continúa implementándose non-preemptive multitasking
.
en el ejemplo gist
puede ejecutar el ejemplo con un parámetro de línea de comandos que seleccione la entrada CLI de bloqueo o no bloqueo.
asyncExample.js
El código que bloquea seguirá bloqueando. Si no fuera así, podrías tener carreras de datos. La idea de las funciones asíncronas es que puede detenerse en el lugar para esperar la ejecución posterior del código asíncrono. Así que te detienes mientras esperas que se complete algo asíncrono, como un
setTimeout
una respuesta XHR o un evento de clic: jsfiddle.net/wgqyayhr (La demostración necesita un navegador con soporte)– usuario1106925
13/03/2017 a las 21:54
async/await
es no parte de ES7 (ES2016). Será parte del lanzamiento de este año, ES2017.– Félix Kling
16 de marzo de 2017 a las 6:18