+ =的异步功能 [英] Async function with +=
问题描述
let x = 0;
async function test() {
x += await 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
记录的x
的值为1
和5
.我的问题是:为什么第二个日志中的x
5
的值是多少?
如果test
在x += 1
之后执行(因为它是一个异步函数),则x的值在执行test
时为1,因此x += await 5
应该将x
的值6
.
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
,因此变成...
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;
}
let x = 0;
async function test() {
x += await 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
The values of x
logged are 1
and 5
. My question is: why is the value of x
5
on second log?
If the test
is executed after x += 1
(since it is an async function) then the value of x is 1 by the time test
is executed, so x += await 5
should make the value of x
6
.
TL;DR: Because +=
reads x
before, but writes it after it has changed, due to the await
keyword in its second operand (right-hand side).
async
functions run synchronously when they called until the first await
statement.
So, if you remove await
, it behaves like a normal function (with the exception that it still returns a Promise).
In that case, you get 5
(from the function) and 6
(from the main script) in the console:
let x = 0;
async function test() {
x += 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
The first await
stops synchronous running, even if its argument available synchronously, so the following will return 1
(from the main script) and 6
(from the function), as you expect:
let x = 0;
async function test() {
// Enter asynchrony
await 0;
x += 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
However, your case is a bit more complicated.
You've put await
inside an expression, that uses +=
.
You probably know, that in JS x += y
is identical to x = (x + y)
. I'll use the latter form for better understanding:
let x = 0;
async function test() {
x = (x + await 5);
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
When the interpreter reaches this line...
x = (x + await 5);
...it starts evaluating it, substitutes x
, so it turns to...
x = (0 + await 5);
...then, it reaches the await
and stops.
The code after the function call starts to run, and modifies the value of x
, then logs it.
x
is now 1
.
Then, after the main script exits, the interpreter goes back to the paused test
function, and continues evaluating that line:
x = (0 + 5);
And, since the value of x
is already substituted, it remains 0
.
Finally, the interpreter does the addition, stores 5
to x
, and logs it.
You can check this behaviour by logging inside an object property getter/setter (in this example, y.z
, which reflects the value of 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;
}
这篇关于+ =的异步功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!