TL; DR: Porque +=lê xantes, mas grava após alterar, devido à awaitpalavra - chave em seu segundo operando (lado direito).
asyncAs funções são executadas de forma síncrona quando foram chamadas até a primeira awaitinstrução.
Portanto, se você remover await, ele se comportará como uma função normal (com a exceção de que ainda retorna uma promessa).
Nesse caso, você obtém 5e 6no console:
let x = 0;
async function test() {
x += 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
A primeira awaitinterrompe a execução síncrona, mesmo que seu argumento esteja disponível de forma síncrona; portanto, o seguinte retornará 1e 6, conforme o esperado:
let x = 0;
async function test() {
// Enter asynchrony
await 0;
x += 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
No entanto, seu caso é um pouco mais complicado.
Você colocou awaitdentro de uma expressão que usa +=.
Você provavelmente sabe que em JS x += yé idêntico a x = (x + y). Usarei o último formulário para entender melhor:
let x = 0;
async function test() {
x = (x + await 5);
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Quando o intérprete chega a esta linha ...
x = (x + await 5);
... começa a avaliar e passa a ...
x = (0 + await 5);
... então, chega ao awaite para.
O código após a chamada da função começa a ser executado, modifica o valor de xe registra-o.
xé agora 1.
Depois que o script principal é encerrado, o intérprete retorna à testfunção em pausa e continua avaliando essa linha:
x = (0 + 5);
E, como o valor de xjá está substituído, ele permanece 0.
Finalmente, o intérprete faz a adição, lojas 5para x, e registra-lo.
Você pode verificar esse comportamento efetuando login em um getter / setter de propriedade de objeto (neste exemplo, y.zreflete o 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)ex += await 5.