赋值运算符、映射和承诺。该代码有啥问题? Javascript
Posted
技术标签:
【中文标题】赋值运算符、映射和承诺。该代码有啥问题? Javascript【英文标题】:Assignment operator, map and promises. What's wrong with that code ? Javascript赋值运算符、映射和承诺。该代码有什么问题? Javascript 【发布时间】:2020-06-19 22:06:04 【问题描述】:我正在做一些事情,但遇到了一个我无法理解的问题。 我简化了代码来得到它:
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'));
你期待什么结果?
1 完成
已记录。
当我改变时
count += await somePromise();
到
const nb = await somePromise();
count += nb;
我明白了
5 完成
我第一次期待的。
你能帮我找出问题所在吗?没看懂。
【问题讨论】:
【参考方案1】:当解释器遇到await
时,它会暂停函数,直到 Promise 解决。即使 Promise 立即解决,该功能也只会在下一个微任务期间恢复。相反,数组通过立即同步迭代。当你这样做时
const promises = arr.map(async () =>
count += await somePromise();
)
在数组被迭代之后,但在await
s 已经解析之前,count
的“当前”值被+=
使用被检索before await
解析 - 之前 count
的值为 0。因此,在解释器看来,好像有 5 个单独的语句:
count += await somePromise();
count += await somePromise();
count += await somePromise();
count += await somePromise();
count += await somePromise();
解析为类似
const currentValueOfCount = count;
count = currentValueOfCount + await somePromise();
count = currentValueOfCount + await somePromise();
count = currentValueOfCount + await somePromise();
count = currentValueOfCount + await somePromise();
count = currentValueOfCount + await somePromise();
因此,=
的右侧每次都解析为 0 + 1
,因此在循环结束时,count
仅是 1。
如果您对规范中的描述感兴趣,请查看assignment operators 的语义。其中+=
是AssignmentOperator
s 之一,语法如下:
LeftHandSideExpressionAssignmentOperatorAssignmentExpression
做:
设 lref 为计算 LeftHandSideExpression 的结果。 让 lval 成为?获取值(lref)。 设 rref 为评估 AssignmentExpression 的结果。 让 rval 是 ?获取值(rref)。 让 op 为 @,其中 AssignmentOperator 为 @=。 令 r 为将 op 应用于 lval 和 rval 的结果,就像评估表达式 lval op rval。
查看lval
是如何在评估运算符右侧之前立即检索的。 (如果lval
被检索到 右侧,AssignmentExpression
,被评估,结果将是 5,正如你所期望的)
这是一个没有异步操作的例子:
let num = 5;
const fn = () =>
num += 3;
return 0;
num += 2 + fn();
console.log(num);
在上面,num += 2 + fn();
立即将num
检索为5
以用于+=
,然后调用fn()
。虽然num
在fn
内部被重新赋值,但它没有任何作用,因为num
的值已经被外部+=
检索到了。
使用你的工作代码,当你这样做时
const nb = await somePromise();
count += nb;
这会将somePromise
的解析值放入nb
变量中,然后 count += nb;
将运行。这符合预期,因为用于+=
的count
的“当前”值是在Promise 解决后检索的,因此如果先前的迭代重新分配count
,它将被成功纳入到下一次迭代为止。
【讨论】:
非常感谢您令人印象深刻的详细回复!我现在明白了以上是关于赋值运算符、映射和承诺。该代码有啥问题? Javascript的主要内容,如果未能解决你的问题,请参考以下文章