+ =的异步功能 [英] Async function with +=

查看:48
本文介绍了+ =的异步功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 let x = 0;

async function test() {
    x += await 5;
    console.log('x :', x);
}

test();
x += 1;
console.log('x :', x); 

记录的x的值为15.我的问题是:为什么第二个日志中的x 5的值是多少?

如果testx += 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆