异步调用栈执行间隙
Asynchronous call stack execution gap
我正在阅读“Eloquent JavaScript”,在异步章节的末尾有一个关于异步操作执行间隙的部分,它展示了一个例子。本书下面的示例代码无法运行,因为它使用了一些虚构的场景。
function anyStorage(nest, source, name) {
if (source == nest.name) return storage(nest, name); else return routeRequest(nest, source, "storage", name);
}
async function chicks(nest, year) {
let list = "";
await Promise.all(network(nest).map(async name => {
list += `${name}: ${
await anyStorage(nest, name, `chicks in ${year}`)
}\n`; }));
return list;
}
它说这段代码的问题,据我所知,是每个异步调用,例如anyStorage
实际上会连接一个空的 list
并且看不到来自其他异步调用的突变。
我尝试如下重现这个问题:
function delay(n) {
return Promise.resolve(setTimeout(()=>{}, n*1000));
}
async function asyncSum(a) {
let sum = 0;
await Promise.all(a.map(async i => sum += await delay(i)));
return sum;
}
asyncSum([1,2,3,4]).then(value => console.log(value));
但这按预期工作。它正确打印总和。
那么是我误解了这本书还是我的例子有问题?
原代码中的问题在于:
list += `${name}: ${ await ...
list +=
就像做 list = list +
- 但第二个列表:
list = list +
^^^^
指的是 list
在那一刻 - 在任何异步调用完成之前。最终其中一个将完成并分配给 list
。但是一旦下一个解析出来,因为它的list
指的是原来的,不是新更新的,之前的结果就会丢失
这是一个演示:
const getMultipliedNum = num => Promise.resolve(num * 3);
(async() => {
let list = "";
await Promise.all([1, 2, 3].map(async num => {
list += `${num}: ${ await getMultipliedNum(num)}\n`;
}));
console.log(list);
})();
你的例子有同样的问题,尽管 delay
函数被破坏了——结果是 4,这只是最终 setTimeout
调用的结果(因为 setTimeout
returns超时ID)。修复它以演示问题:
function delay(n) {
return Promise.resolve(n);
}
async function asyncSum(a) {
let sum = 0;
await Promise.all(a.map(async i => sum += await delay(i)));
return sum;
}
asyncSum([1,2,3,4]).then(value => console.log(value));
结果是 4,而不是 10 - 这表明并行循环中的 sum += await somethingElse
不起作用。
另一种看待它的方式:
sum += await somethingElse
就像在做
const currentValueOfSum = sum;
sum = currentValueOfSum + await somethingElse;
我正在阅读“Eloquent JavaScript”,在异步章节的末尾有一个关于异步操作执行间隙的部分,它展示了一个例子。本书下面的示例代码无法运行,因为它使用了一些虚构的场景。
function anyStorage(nest, source, name) {
if (source == nest.name) return storage(nest, name); else return routeRequest(nest, source, "storage", name);
}
async function chicks(nest, year) {
let list = "";
await Promise.all(network(nest).map(async name => {
list += `${name}: ${
await anyStorage(nest, name, `chicks in ${year}`)
}\n`; }));
return list;
}
它说这段代码的问题,据我所知,是每个异步调用,例如anyStorage
实际上会连接一个空的 list
并且看不到来自其他异步调用的突变。
我尝试如下重现这个问题:
function delay(n) {
return Promise.resolve(setTimeout(()=>{}, n*1000));
}
async function asyncSum(a) {
let sum = 0;
await Promise.all(a.map(async i => sum += await delay(i)));
return sum;
}
asyncSum([1,2,3,4]).then(value => console.log(value));
但这按预期工作。它正确打印总和。 那么是我误解了这本书还是我的例子有问题?
原代码中的问题在于:
list += `${name}: ${ await ...
list +=
就像做 list = list +
- 但第二个列表:
list = list +
^^^^
指的是 list
在那一刻 - 在任何异步调用完成之前。最终其中一个将完成并分配给 list
。但是一旦下一个解析出来,因为它的list
指的是原来的,不是新更新的,之前的结果就会丢失
这是一个演示:
const getMultipliedNum = num => Promise.resolve(num * 3);
(async() => {
let list = "";
await Promise.all([1, 2, 3].map(async num => {
list += `${num}: ${ await getMultipliedNum(num)}\n`;
}));
console.log(list);
})();
你的例子有同样的问题,尽管 delay
函数被破坏了——结果是 4,这只是最终 setTimeout
调用的结果(因为 setTimeout
returns超时ID)。修复它以演示问题:
function delay(n) {
return Promise.resolve(n);
}
async function asyncSum(a) {
let sum = 0;
await Promise.all(a.map(async i => sum += await delay(i)));
return sum;
}
asyncSum([1,2,3,4]).then(value => console.log(value));
结果是 4,而不是 10 - 这表明并行循环中的 sum += await somethingElse
不起作用。
另一种看待它的方式:
sum += await somethingElse
就像在做
const currentValueOfSum = sum;
sum = currentValueOfSum + await somethingElse;