【问题标题】:How to synchronize an async map function in javascript如何在 javascript 中同步异步映射函数
【发布时间】:2020-12-24 12:15:08
【问题描述】:

我有一个异步映射函数,但希望它同步执行,因为我需要在同一个循环中使用第一条语句的输出。但是即使使用 await 语句,地图也会异步运行,请您帮助理解为什么会发生这种情况。

我的用例是如果不存在则将记录插入 mongodb 并在循环中存在时更新它。 数据存在于数据库中,但在循环内查找失败,但在外部工作。

我的代码:

        const doSomethingAsync = () => {
            return new Promise(resolve => {
                setTimeout(() => {
                    resolve(Date.now());
                }, 1000);
            });
        };

        await Promise.all(
            modelVarients.map(async varient => {
                console.log(`varient: ${varient._id}`);
                console.log('1');
                const onlineDevice = await Device.findOne({
                    model: varient._id,
                });
                console.log('2');
                await doSomethingAsync();
                console.log('3');
                await doSomethingAsync();
                console.log(JSON.stringify(onlineDevice));
                await doSomethingAsync();
                console.log('4');
                return varient;
            })
        );

我得到的日志:

varient: 8 pro
1
varient: note
1
varient: iphone x
1
2
2
2
3
3
3
null
null
null
4
4
4

但我期望得到的:

varient: 8 pro
1
2
3
<actual response from db for 8 pro>
4
varient: note
1
2
3
<actual response from db for note>
4
varient: iphone x
1
2
3
<actual response from db for iphone x>
4

【问题讨论】:

  • 使用 await modeVariants.reduce( async (...) => ) 而不是 map
  • @olkvin 谢谢,我会尝试在我的代码中实现
  • @EdwardRomero 感谢您向我指出一个类似的问题,是的,它帮助我了解了 reduce 以及如何链接承诺,下面来自 sashee 使用 async/await 的答案也非常有帮助

标签: javascript node.js asynchronous async-await async.js


【解决方案1】:

看起来你应该链接你的承诺,而不是与Promise.all并行运行

【讨论】:

    【解决方案2】:

    modelVarients.map(async () =&gt; &gt;...) 将所有元素转换为 Promise,这意味着它们都开始执行。然后Promise.all() 收集它们并等待所有这些,这就是为什么你可以使用这个结构来等待map 完成。这是并行处理。

    您需要的是顺序处理,您可以使用reduce 来完成,如下所示:

    await modelVarients.reduce(async (memo, varient) => {
        await memo;
        // all the other things
    }, Promise.resolve())
    

    reduce 在某种意义上类似于map,它为数组中的所有元素创建一个 Promise,但是有一个 当前值 从一个元素传递到另一个元素.在这种情况下,第一个是Promise.resolve(),第二个是第一个的结果,依此类推。使用await memo,您可以等待上一个结果。

    使用reduce,最后一个元素将等待前一个元素,它等待前一个元素,以此类推,因此不需要Promise.all。

    我写过关于 mapreduce 如何使用异步函数的文章,它们将帮助您了解全局。

    【讨论】:

    • 使用reduceasync function 作为回调是一个坏主意,它效率低下而且很容易完全出错。
    • @Bergi 你能详细说明为什么你认为这是一个坏主意,当我研究 reduce 时,甚至官方文档也有一个类似的例子 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
    • @Sai 使用的是then 而不是await,并且在数组中链接(少数)不同的函数,而不是在数组中的(许多)项上链接相同的函数。
    • 一般来说,只需使用for … of 循环和await - 更简单、更短、更快。
    • es-lint 不鼓励 for ... of when 此错误:“迭代器/生成器需要 regenerator-runtime,这对于本指南来说太重了,无法允许它们。另外,应避免循环以支持数组迭代。” eslint.org/docs/rules/no-restricted-syntax 有什么想法吗?
    猜你喜欢
    • 2019-07-10
    • 1970-01-01
    • 2020-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-25
    • 2021-03-06
    • 2016-07-05
    相关资源
    最近更新 更多