【问题标题】:for..in loop for asynchronous tasks in Javascriptfor..in 循环用于 Javascript 中的异步任务
【发布时间】:2019-05-08 21:17:26
【问题描述】:

我有一个关联容器(键/值,“哈希”)。我使用 for..in 循环对其进行迭代:

for (key in container) {
   doSomethingWith(key, container[key]
}

现在我希望 doSomethingWith() 返回一个承诺(Q 或标准承诺),并且我想按顺序迭代,而不是并行迭代。也就是说,我希望每次调用 doSomethingWith() 在再次调用它之前解决它的承诺。

我该怎么做?

  1. 有没有一种方法可以在不使用 Object.keys() (在我的情况下很长)和索引的情况下迭代键?新的 Map 类有用吗?

  2. 可能已经有人写过。另外,如果我想要有限的并发性(例如,本着 make -j 10 的精神,正在进行 10 次 somethingWith()),复杂性会爆炸,因此某个地方必须存在一个成熟的实现。

  3. 我究竟如何链接它?我的看法是使用一个从 done() 调用自身的辅助函数:


function forEachKey(obj, doSomething) {
    const q = Q.defer()
    const keys = Object.keys(obj)
    const idx = 0
    const helper = () =>
       if (idx < keys.length) {
           doSomething(idx).done(helper)
           idx += 1
       }
       else
       {
          q.resolve()
       }
}

【问题讨论】:

  • 只需使用async/await。这是最简单、最有效的解决方案。
  • 要顺序解决一组承诺,你可以这样做Object.keys(obj).reduce((p, k) =&gt; p.then(() =&gt; doSomething(k)), Promise.resolve())
  • Array.prototype.reduce() 是同步的。我既不能使用它也不能使用 foreach。如果支持从 for..in 内部屈服,它可能是有希望的。我试试看
  • 是的,迭代是同步的,但是解析是异步的。我还没有机会和async iterators 一起玩,因为他们还在选秀中。

标签: javascript foreach promise hashmap


【解决方案1】:

这是一个非常简单的演示,但我认为这显示了如何使用 async/await 来实现您所需要的。

const container = {
  name: "test",
  value: "test2"
};

const doSomethingWith = (x, y) => new Promise((resolve, reject) => {
  console.log(x);
  resolve(x);
});

(async() => {
  for (let key in container) {
    await doSomethingWith(key, container[key]);
  }
})();

【讨论】:

    【解决方案2】:

    您需要做出一系列承诺。这是一个reduce的例子:

    Object.keys(obj).reduce((promiseSoFar, key) => 
      promiseSoFar.then(() => doSomethingWith(key, container[key])
    , Promise.resolve());
    

    有没有办法在不诉诸 Object.keys() (在我的情况下很长)和索引的情况下迭代键

    我不确定对 Object.keys 的厌恶是什么,但是是的,您可以在没有 Object.keys 的情况下构建承诺链

    let promiseSoFar = Promise.resolve();
    for (let key in container) {
       promiseSoFar = promiseSoFar.then(() => doSomethingWith(key, container[key]));
    }
    

    【讨论】:

    • 有十万到亿个键。所以承诺链或 Object.keys 可能会很重。
    【解决方案3】:

    由于我在节点 4.9.1 上,我无法使用 async/await。所以这是我自己使用yield的看法:

    function* keyGenerator(obj)
    {
        for (const key in obj)
        {
            yield key
        }
    }
    
    exports.asyncForIn = function (obj, doSomething)
    {
        const keyGen = keyGenerator(obj)
        const q = Q.defer()
    
        const rec = () => {
            const i = keyGen.next()
            if (!i.done)
            {
                doSomething(i.value).done(rec, (x) => q.reject(x))
            }
            else
            {
                q.resolve()
            }
        }
        rec()
        return q.promise
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-13
      • 1970-01-01
      • 2017-09-30
      • 1970-01-01
      • 2018-06-22
      相关资源
      最近更新 更多