TL; DR: Perché +=
legge x
prima, ma lo scrive dopo che è stato modificato, a causa della await
parola chiave nel suo secondo operando (lato destro).
async
le funzioni vengono eseguite in modo sincrono quando hanno chiamato fino alla prima await
istruzione.
Quindi, se lo rimuovi await
, si comporta come una normale funzione (con l'eccezione che restituisce comunque una Promessa).
In tal caso, ottieni 5
e 6
nella console:
let x = 0;
async function test() {
x += 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Il primo await
interrompe l'esecuzione sincrona, anche se l'argomento è disponibile in modo sincrono, quindi verrà restituito quanto segue 1
e 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 await
dentro 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 await
e 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 test
funzione 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 5
a x
, e lo registra.
È possibile verificare questo comportamento accedendo a un oggetto getter / setter della proprietà dell'oggetto (in questo esempio, y.z
riflette 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
.