TL; DR: Bởi vì +=
đọc x
trước, nhưng viết nó sau khi nó đã thay đổi, do await
từ khóa trong toán hạng thứ hai của nó (phía bên tay phải).
async
các hàm chạy đồng bộ khi chúng được gọi cho đến await
câu lệnh đầu tiên .
Vì vậy, nếu bạn loại bỏ await
, nó hoạt động như một hàm bình thường (với ngoại lệ là nó vẫn trả về một Promise).
Trong trường hợp đó, bạn nhận 5
và 6
trong bảng điều khiển:
let x = 0;
async function test() {
x += 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Cái đầu tiên await
dừng chạy đồng bộ, ngay cả khi đối số của nó có sẵn đồng bộ, do đó, phần sau sẽ trả về 1
và 6
, như bạn mong đợi:
let x = 0;
async function test() {
// Enter asynchrony
await 0;
x += 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Tuy nhiên, trường hợp của bạn phức tạp hơn một chút.
Bạn đã đặt await
trong một biểu thức, sử dụng +=
.
Bạn có thể biết, rằng trong JS x += y
là giống hệt nhau x = (x + y)
. Tôi sẽ sử dụng mẫu sau để hiểu rõ hơn:
let x = 0;
async function test() {
x = (x + await 5);
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Khi thông dịch viên đạt đến dòng này ...
x = (x + await 5);
... nó bắt đầu đánh giá nó, và nó chuyển sang ...
x = (0 + await 5);
... Sau đó, nó đạt đến await
và dừng lại.
Mã sau khi gọi hàm bắt đầu chạy và sửa đổi giá trị của x
, sau đó ghi nhật ký.
x
tại là 1
.
Sau đó, sau khi tập lệnh chính thoát, trình thông dịch quay trở lại test
chức năng bị tạm dừng và tiếp tục đánh giá dòng đó:
x = (0 + 5);
Và, vì giá trị của x
đã được thay thế, nó vẫn còn 0
.
Cuối cùng, người phiên dịch làm việc bổ sung, các cửa hàng 5
để x
, và ghi lại nó.
Bạn có thể kiểm tra hành vi này bằng cách đăng nhập bên trong một getter / setter thuộc tính đối tượng (trong ví dụ này, y.z
phản ánh giá trị của 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)
vàx += await 5
.