简体   繁体   English

异步调用栈执行间隙

[英]Asynchronous call stack execution gap

I am reading "Eloquent JavaScript" and at the end of Asynchronous chapter there is a section about execution gap in asynchronous operations and it shows an example.我正在阅读“Eloquent JavaScript”,在异步章节的末尾有一个关于异步操作中的执行间隙的部分,它显示了一个示例。 The example code below from the book is not runable as it uses some made up scenario.本书下面的示例代码不可运行,因为它使用了一些虚构的场景。

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;
 }

It says the problem with this code, as I understand, is each asynchronous call eg anyStorage will actually concatenate an empty list and can't see the mutation from other asynchronous calls.据我了解,它说这段代码的问题是每个异步调用,例如anyStorage实际上会连接一个空list ,并且看不到来自其他异步调用的突变。

I tried to replicate this problem as below:我试图复制这个问题如下:

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));

But this works as expected.但这按预期工作。 It prints the sum correctly.它正确打印总和。 So did I misunderstand the book or there is something wrong with my example?那么是我误解了这本书还是我的例子有问题?

The problem in the original code is that here:原始代码中的问题在于:

list += `${name}: ${ await ...

The list += is like doing list = list + - but the second list: list +=就像做list = list + - 但第二个列表:

list = list +
       ^^^^

refers to the list at that moment - before any of the asynchronous calls have completed.当时list - 在任何异步调用完成之前。 Eventually one of them will complete and assigns to list .最终其中一个将完成并分配给list But once the next one resolves, because the list it has refers to the original one, not the newly updated one, the prior results will be lost.但是一旦下一个解析,因为它的list是指原始的,而不是新更新的,之前的结果将丢失。

Here's a demo:这是一个演示:

 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); })();

Your example has the same issue, though the delay function is broken - the result is 4, which is only the result of the final setTimeout call (because setTimeout returns the timeout ID).您的示例有同样的问题,尽管delay功能被破坏 - 结果是 4,这只是最终setTimeout调用的结果(因为setTimeout返回超时 ID)。 Fixing it to demonstrate the problem:修复它以演示问题:

 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));

The result is 4, rather than 10 - this demonstrates that sum += await somethingElse inside a parallel loop doesn't work.结果是 4,而不是 10 - 这表明sum += await somethingElse在并行循环中不起作用。

Another way of looking at it:另一种看待它的方式:

sum += await somethingElse

is like doing就像在做

const currentValueOfSum = sum;
sum = currentValueOfSum + await somethingElse;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM