【问题标题】:Non-recursive method to iterate over Promise iterator迭代 Promise 迭代器的非递归方法
【发布时间】:2016-07-21 14:02:06
【问题描述】:

我开发了一个客户端库,它公开了一个名为iterator() 的方法。该方法返回一个使用require('promise')库创建的Promise实例,该实例由一个迭代器对象完成。

此对象包含一个名为 next() 的方法,该方法返回一个 Promise,该 Promise 由一个复杂的对象完成,如下所示:{done: [true|false], key: _, value: _}

尽管iterator() 可能会预取一些元素,next() 需要返回一个 Promise 以防它导致远程调用。

现在,假设用户想要遍历所有元素,直到 next() 返回的 Promise 返回包含 done: true 的对象。

我已经设法使用以下递归方法实现了这一点(我最初在answer 中找到了这个解决方案):

var iterate = client.iterator();

iterateTeams.then(function(it) {

  function loop(promise, fn) {
    // Simple recursive loop over iterator's next() call
    return promise.then(fn).then(function (entry) {
      return !entry.done ? loop(it.next(), fn) : entry;
    });
  }

  return loop(it.next(), function (entry) {
    console.log('entry is: ' + entry);
    return entry;
  });

});

问题是,是否有可能使用require('promise') 库来构建非递归解决方案?我对非递归方法感兴趣的原因是,如果要迭代的条目数量太大,可以避免崩溃。

干杯, 高德

【问题讨论】:

  • 听起来你正在寻找一个生成器或可观察对象。
  • 您可以使用另一种解决方案,为您隐藏递归,但它仍然是递归解决方案
  • Galder,您可能想阅读标题为“The Collection Kerfuffle”的部分here
  • 我们还没有到达那里,但是已经到达那里了:) 查看答案。
  • @Roamer-1888,感谢您的指点,但该部分假定您有一个数组或知道您需要循环多少个元素,因此不适用于此处。

标签: javascript promise


【解决方案1】:

我对非递归方法感兴趣的原因是,如果要迭代的条目数量太大,可以避免崩溃

别害怕。异步“递归”(有时称为pseudo-recursion)不会增加调用堆栈,它很像尾递归。您永远不会遇到 stackoverflow 异常。

如果合理地实现了 Promise 库,这甚至不会增加内存 - 详情请参阅 Building a promise chain recursively in javascript - memory considerations

【讨论】:

    【解决方案2】:

    没有新语法或库 - 通常不会。

    好吧,如果你使用 babel,你可以使用 ES2018 (:P) 异步迭代:

    for await (const team of iterateTeams) {
       // do something with team
    }
    

    read more about it here

    否则,您可以使用具有 ES2016 async/await 语法的生成器:

    for(var it = iterateTeams(); !done; ({done, value}) = await it.next()) {
        // work with value
    }     
    

    或者使用今天可用的 ES2015 生成器语法和通过 bluebird 的泵:

    // inside a Promise.corutine  
    for(var it = iterateTeams(); !done; ({done, value}) = yield it.next()) {
       // work with value
    }     
    

    【讨论】:

    • 非常感谢这些解决方案,但没有一个对我有用。我正在使用 ES2015 并且需要 Node.js 0.10(bluebird Promise.coroutine 需要 Node.js 0.12)。
    • @GalderZamarreño 如果您使用的是 NodeJS 0.10,您如何使用 ES2015?
    • 此外,答案仍然有效,没有递归或递归本身的辅助方法 - 在 ES2015 之前这是不可能的
    • 抱歉,弄糊涂了,意思是 ES5 和 Node.js 0.10。
    • 那么不,您必须使用递归或使用递归本身的辅助函数 - 有效地将您的 loop 函数提取到辅助函数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-07
    • 2021-12-24
    • 1970-01-01
    • 1970-01-01
    • 2016-11-10
    相关资源
    最近更新 更多