let x = 0;
async function test() {
x += await 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Los valores de xlogueado son 1y 5. Mi pregunta es: ¿por qué es el valor de x 5en el segundo registro?
Si testse ejecuta después x += 1(dado que es una función asíncrona), el valor de x es 1 en el momento en que testse ejecuta, por lo que x += await 5debe ser el valor de x 6.
javascript
async-await
event-loop
ALDRIN P VINCENT
fuente
fuente

await (x += 5)yx += await 5.Respuestas:
TL; DR: Porque
+=leexantes, pero lo escribe después de que ha cambiado, debido a laawaitpalabra clave en su segundo operando (lado derecho).asyncLas funciones se ejecutan sincrónicamente cuando llaman hasta la primeraawaitinstrucción.Entonces, si elimina
await, se comporta como una función normal (con la excepción de que aún devuelve una Promesa).En ese caso, obtienes
5y6en la consola:El primero
awaitdetiene la ejecución síncrona, incluso si su argumento está disponible sincrónicamente, por lo que se devolverá lo siguiente1y6, como es de esperar:Sin embargo, su caso es un poco más complicado.
Has puesto
awaitdentro de una expresión, que usa+=.Probablemente sepa que en JS
x += yes idéntico ax = (x + y). Usaré la última forma para una mejor comprensión:Cuando el intérprete llega a esta línea ...
... comienza a evaluarlo, y se convierte en ...
... entonces, llega al
awaity se detiene.El código después de la llamada a la función comienza a ejecutarse y modifica el valor de
x, luego lo registra.xes ahora1.Luego, una vez que sale el guión principal, el intérprete vuelve a la
testfunción en pausa y continúa evaluando esa línea:Y, dado que el valor de
xya está sustituido, permanece0.Por último, el intérprete hace la adición, tiendas
5dex, y lo registra.Puede verificar este comportamiento iniciando sesión dentro de un objeto getter / setter (en este ejemplo,
y.zrefleja el valor dex:fuente
x += yes idéntico ax = (x + y)". - Este no es el caso en todas las situaciones en todos los idiomas, pero en general puede contar con que actúen de la misma manera.Su declaración se
x += await 5desugará aEl
_tempvalor orario es0, y si cambiaxduranteawait(lo que hace su código) no importa, se asigna5después.fuente
Este código es bastante complejo de seguir porque requiere algunos saltos asíncronos inesperados de un lado a otro. Examinemos (cerca de) cómo se ejecutará realmente y luego explicaré por qué. También he cambiado los registros de la consola para agregar un número, lo que facilita la referencia a ellos y también muestra mejor lo que se registra:
Por lo tanto, el código en realidad no funciona de manera directa, eso es seguro. Y también tenemos
4/7algo extraño . Y eso es realmente la totalidad del problema aquí.En primer lugar, aclaremos: las funciones asincrónicas no son realmente estrictamente asincrónicas. Solo pausarían la ejecución y reanudarían más tarde si
awaitse usa la palabra clave. Sin ella, ejecutan de arriba a abajo, expresión tras expresión sincrónicamente:Entonces, lo primero que necesitamos saber es que usar
awaithará que el resto de la función se ejecute más tarde. En el ejemplo dado, eso significa queconsole.log('x1 :', x)se ejecutará después del resto del código síncrono. Esto se debe a que cualquier Promesa se resolverá una vez que finalice el ciclo del evento actual.Entonces, esto explica por qué nos
x2 : 1registramos primero y por quéx2 : 5se registra en segundo lugar, pero no por qué es el último valor5. Lógicamentex += await 5debería ser5... pero aquí está la segunda captura de laawaitpalabra clave: pausará la ejecución de la función, pero cualquier cosa antes de que ya se haya ejecutado.x += await 5en realidad se va a procesar de la siguiente manerax. En el momento de la ejecución, eso es0.awaitLa siguiente expresión que es5. Por lo tanto, la función se detiene ahora y se reanudará más adelante.0 + 5xPor lo tanto, las pausas función después de que leyeron que
xes0y se reanuda cuando ya ha cambiado, sin embargo, no volver a leer el valor dex.Si desenvolvemos el equivalente
awaiten elPromiseequivalente que se ejecutaría, tiene:fuente
Sí, es un poco complicado lo que realmente está sucediendo, ambas operaciones de suma están sucediendo de manera paralela, por lo que la operación sería como:
Dentro de la promesa:
x += await 5==>x = x + await 5==>x = 0 + await 5==>5Afuera:
x += 1==>x = x + 1==>x = 0 + 1==>1Como todas las operaciones anteriores se realizan de izquierda a derecha, la primera parte de la suma puede calcularse al mismo tiempo y dado que hay una espera antes de las 5, esa adición puede retrasarse un poco. Puede ver la ejecución colocando un punto de interrupción dentro del código.
fuente
Async y Await son extensiones de promesas. Una función asincrónica puede contener una expresión de espera que detiene la ejecución de la función asincrónica y espera la resolución de la Promesa aprobada, y luego reanuda la ejecución de la función asincrónica y devuelve el valor resuelto. Recuerde, la palabra clave await solo es válida dentro de las funciones asíncronas.
Incluso si ha cambiado el valor de x después de llamar a la función de prueba, el valor de x seguirá siendo 0 porque la función asincrónica ya ha creado su nueva instancia. Lo que significa que todo cambia en la variable fuera de ella no cambiará el valor dentro de ella después de que se llamó. A menos que ponga su incremento por encima de la función de prueba.
fuente
let x="Didn't receive change"; (async()=>{await 'Nothing'; console.log(x); await new Promise(resolve=>setTimeout(resolve,2000)); console.log(x)})(); x='Received synchronous change'; setTimeout(()=>{x='Received change'},1000)GeneraReceived synchronous changeyReceived change