TL; DR: Perché +=legge xprima, ma lo scrive dopo che è stato modificato, a causa della awaitparola chiave nel suo secondo operando (lato destro).
asyncle funzioni vengono eseguite in modo sincrono quando hanno chiamato fino alla prima awaitistruzione.
Quindi, se lo rimuovi await, si comporta come una normale funzione (con l'eccezione che restituisce comunque una Promessa).
In tal caso, ottieni 5e 6nella console:
let x = 0;
async function test() {
x += 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Il primo awaitinterrompe l'esecuzione sincrona, anche se l'argomento è disponibile in modo sincrono, quindi verrà restituito quanto segue 1e 6, come previsto:
let x = 0;
async function test() {
// Enter asynchrony
await 0;
x += 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Tuttavia, il tuo caso è un po 'più complicato.
Hai messo awaitdentro un'espressione che usa +=.
Probabilmente sai che in JS x += yè identico a x = (x + y). Userò quest'ultimo modulo per una migliore comprensione:
let x = 0;
async function test() {
x = (x + await 5);
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Quando l'interprete raggiunge questa linea ...
x = (x + await 5);
... inizia a valutarlo e si trasforma in ...
x = (0 + await 5);
... poi raggiunge awaite si ferma.
Il codice dopo la chiamata della funzione inizia a essere eseguito e modifica il valore di x, quindi lo registra.
xè adesso 1.
Quindi, una volta terminato lo script principale, l'interprete torna alla testfunzione in pausa e continua a valutare quella riga:
x = (0 + 5);
E, poiché il valore di xè già sostituito, rimane 0.
Infine, l'interprete fa l'aggiunta, i negozi 5a x, e lo registra.
È possibile verificare questo comportamento accedendo a un oggetto getter / setter della proprietà dell'oggetto (in questo esempio, y.zriflette il valore di 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)ex += await 5.