赋值运算符、映射和承诺。那个代码有什么问题?Javascript

kno*_*ona 5 javascript assignment-operator promise es6-promise

我正在做一些事情,但遇到了一个我无法理解的问题。我简化了代码以获得:

function somePromise() {
    return new Promise((resolve, reject) => {
        resolve(1);
    });
}

async function main() {
    let count = 0;
    const arr = [1, 2, 3, 4, 5];
    const promises = arr.map(async () => {
        count += await somePromise();
    })
    await Promise.all(promises);
    console.log(count);
}

main().then(() => console.log('Done'));
Run Code Online (Sandbox Code Playgroud)

你期待什么结果?

1
完成

已记录。

当我改变

count += await somePromise();
Run Code Online (Sandbox Code Playgroud)

const nb = await somePromise();
count += nb;
Run Code Online (Sandbox Code Playgroud)

我得到

5
完成

我第一次期待的。

你能帮我找出问题所在吗?我不明白。

Cer*_*nce 5

当解释器遇到 时await,它会暂停函数,直到 Promise 解决。即使 Promise 立即解析,该函数也只会在下一个微任务期间恢复。与此相反,该阵列是通过迭代立即,同步。当你做

const promises = arr.map(async () => {
    count += await somePromise();
})
Run Code Online (Sandbox Code Playgroud)

数组迭代后通过,但之前await■找解决的“当前”值count这是采取通过使用+=检索之前await做出决议-和值count在此之前是0,所以,它看起来解释为如果有 5 个单独的语句:

count += await somePromise();
count += await somePromise();
count += await somePromise();
count += await somePromise();
count += await somePromise();
Run Code Online (Sandbox Code Playgroud)

解决了类似的问题

const currentValueOfCount = count;
count = currentValueOfCount + await somePromise();
count = currentValueOfCount + await somePromise();
count = currentValueOfCount + await somePromise();
count = currentValueOfCount + await somePromise();
count = currentValueOfCount + await somePromise();
Run Code Online (Sandbox Code Playgroud)

因此,每次,右侧都=解析为0 + 1,因此在循环结束时,count仅为 1。

如果您对规范中的描述感兴趣,请查看赋值运算符的语义。where+=AssignmentOperators 之一,语法如下:

LeftHandSideExpression AssignmentOperator AssignmentExpression

做:

  1. 令 lref 为评估 LeftHandSideExpression 的结果。
  2. 让 lval ? 获取值(lref)。
  3. 让 rref 是对 AssignmentExpression 求值的结果。
  4. 让 rval ? 获取值(参考)。
  5. 令 op 为 @,其中 AssignmentOperator 为 @=。
  6. 令 r 是将 op 应用于 lval 和 rval 的结果,就像评估表达式 lval op rval 一样。

在评估运算符的右侧之前,查看如何立即lval检索。(如果在右手边之后被检索,则lvalAssignmentExpression,是进行评价的结果将是5,因为你希望)

这是没有异步操作的这种行为的示例:

const promises = arr.map(async () => {
    count += await somePromise();
})
Run Code Online (Sandbox Code Playgroud)

上面,num += 2 + fn();检索numas5立即用于+=,然后调用fn()。虽然num是在 inside 中重新赋值fn,但它没有任何作用,因为 的值num已经被外部 检索到了+=


使用您的工作代码,当您这样做时

const nb = await somePromise();
count += nb;
Run Code Online (Sandbox Code Playgroud)

这会将解析值somePromise放入nb变量中,然后 count += nb;运行。这符合预期,因为在Promise 解析检索countused for的“当前”值,因此如果先前的迭代重新分配,下一次迭代将成功考虑。+=count