TL; DR: Porque +=lee xantes, pero lo escribe después de que ha cambiado, debido a la awaitpalabra clave en su segundo operando (lado derecho).
asyncLas funciones se ejecutan sincrónicamente cuando llaman hasta la primera awaitinstrucció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 5y 6en la consola:
let x = 0;
async function test() {
x += 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
El primero awaitdetiene la ejecución síncrona, incluso si su argumento está disponible sincrónicamente, por lo que se devolverá lo siguiente 1y 6, como es de esperar:
let x = 0;
async function test() {
// Enter asynchrony
await 0;
x += 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
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 a x = (x + y). Usaré la última forma para una mejor comprensión:
let x = 0;
async function test() {
x = (x + await 5);
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Cuando el intérprete llega a esta línea ...
x = (x + await 5);
... comienza a evaluarlo, y se convierte en ...
x = (0 + await 5);
... 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 ahora 1.
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:
x = (0 + 5);
Y, dado que el valor de xya está sustituido, permanece 0.
Por último, el intérprete hace la adición, tiendas 5de x, y lo registra.
Puede verificar este comportamiento iniciando sesión dentro de un objeto getter / setter (en este ejemplo, y.zrefleja el valor de x:
let x = 0;
const y = {
get z() {
console.log('get x :', x);
return x;
},
set z(value) {
console.log('set x =', value);
x = value;
}
};
async function test() {
console.log('inside async function');
y.z += await 5;
console.log('x :', x);
}
test();
console.log('main script');
y.z += 1;
console.log('x :', x);
/* Output:
inside async function
get x : 0 <-- async fn reads
main script
get x : 0
set x = 1
x : 1
set x = 5 <-- async fn writes
x : 5 <-- async fn logs
*/
/* Just to make console fill the available space */
.as-console-wrapper {
max-height: 100% !important;
}
await (x += 5)yx += await 5.