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
.