TL; DR: потому что +=читает xраньше, но записывает после изменения, из-за awaitключевого слова во втором операнде (правая часть).
asyncфункции выполняются синхронно при вызове до первого awaitоператора.
Таким образом, если вы удалите awaitего, он будет вести себя как обычная функция (за исключением того, что он по-прежнему возвращает Promise).
В таком случае вы получаете 5и 6в консоли:
let x = 0;
async function test() {
x += 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Первый awaitостанавливает синхронный запуск, даже если его аргумент доступен синхронно, поэтому возвращается следующее 1и 6, как вы ожидаете:
let x = 0;
async function test() {
// Enter asynchrony
await 0;
x += 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Тем не менее, ваш случай немного сложнее.
Вы поместили awaitв выражение, которое использует +=.
Вы, наверное, знаете, что в JS x += yидентично x = (x + y). Я буду использовать последнюю форму для лучшего понимания:
let x = 0;
async function test() {
x = (x + await 5);
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Когда переводчик достигает этой строки ...
x = (x + await 5);
... он начинает оценивать это и превращается в ...
x = (0 + await 5);
... затем он достигает awaitи останавливается.
Код после вызова функции начинает выполняться и изменяет значение x, затем регистрирует его.
xв настоящее время 1.
Затем, после выхода из основного сценария, интерпретатор возвращается к приостановленной testфункции и продолжает вычислять эту строку:
x = (0 + 5);
И, поскольку значение xуже подставлено, оно остается 0.
Наконец, интерпретатор делает добавление, магазины , 5чтобы xи регистрирует его.
Вы можете проверить это поведение, зарегистрировавшись в свойствах объекта getter / setter (в этом примере y.zотражает значение 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)иx += await 5.