赋值运算符、映射和承诺。该代码有什么问题? Javascript
Assignment operator, map and promises. What's wrong with that code ? Javascript
我正在做一些事情,然后 运行 遇到了一个我无法理解的问题。
我简化了代码以获得:
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
Done
已记录。
当我改变
count += await somePromise();
至
const nb = await somePromise();
count += nb;
我明白了
5
Done
这是我第一次期待的。
你能帮我找出问题所在吗?没看懂。
当解释器遇到 await
时,它会暂停函数直到 Promise 的解析。即使 Promise 立即 resolve,函数也只会在下一个微任务期间恢复。相反,数组通过 立即 同步迭代。当你这样做时
const promises = arr.map(async () => {
count += await somePromise();
})
数组遍历后,但之前 await
s 已解析,count
的"current" 值被采用+=
的使用在 之前 被检索 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
之一,语法如下:
LeftHandSideExpression AssignmentOperator AssignmentExpression
会:
- Let lref be the result of evaluating LeftHandSideExpression.
- Let lval be ? GetValue(lref).
- Let rref be the result of evaluating AssignmentExpression.
- Let rval be ? GetValue(rref).
- Let op be the @ where AssignmentOperator is @=.
- Let r be the result of applying op to lval and rval as if evaluating the expression 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
的 "current" 值在 Promise 解析后被检索,因此如果先前的迭代重新分配 count
,下一次迭代将成功考虑它。
我正在做一些事情,然后 运行 遇到了一个我无法理解的问题。 我简化了代码以获得:
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
Done
已记录。
当我改变
count += await somePromise();
至
const nb = await somePromise();
count += nb;
我明白了
5
Done
这是我第一次期待的。
你能帮我找出问题所在吗?没看懂。
当解释器遇到 await
时,它会暂停函数直到 Promise 的解析。即使 Promise 立即 resolve,函数也只会在下一个微任务期间恢复。相反,数组通过 立即 同步迭代。当你这样做时
const promises = arr.map(async () => {
count += await somePromise();
})
数组遍历后,但之前 await
s 已解析,count
的"current" 值被采用+=
的使用在 之前 被检索 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
之一,语法如下:
LeftHandSideExpression AssignmentOperator AssignmentExpression
会:
- Let lref be the result of evaluating LeftHandSideExpression.
- Let lval be ? GetValue(lref).
- Let rref be the result of evaluating AssignmentExpression.
- Let rval be ? GetValue(rref).
- Let op be the @ where AssignmentOperator is @=.
- Let r be the result of applying op to lval and rval as if evaluating the expression 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
的 "current" 值在 Promise 解析后被检索,因此如果先前的迭代重新分配 count
,下一次迭代将成功考虑它。