非递归方法遍历 Promise 迭代器

6
我开发了一个客户端库,其中包括一个名为 iterator() 的方法。该方法返回一个Promise实例,使用require('promise')库创建完成一个迭代器对象。
此对象包含一个名为next()的方法,它返回一个Promise对象,该对象被完成后将返回一个类似于这样的复杂对象:{done: [true|false], key: _, value: _}
虽然 iterator() 可能会预取一些元素,但如果需要进行远程调用,则next()需要返回一个Promise对象。
现在,假设用户想要迭代所有元素,直到由next()返回一个包含done:true的对象为止。
我已经使用以下递归方法实现了这一点(最初我在这个答案中找到了这个解决方案):
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

听起来你正在寻找一个生成器或可观察对象。 - ssube
你可以使用另一种解决方案,它会为你“隐藏”递归,但它仍然是一个递归解决方案。 - smnbbrv
我们还没有到达目标,但已经接近了 :) 请查看答案。 - Benjamin Gruenbaum
@Roamer-1888,感谢您的指引,但该部分假定您有一个数组或知道需要循环遍历多少个元素,因此在这里不适用。 - Galder Zamarreño
@Bergi,你能把那个作为一个解决方案添加吗? - Galder Zamarreño
显示剩余2条评论
2个回答

3

我对非递归方法感兴趣的原因是为了避免在迭代条目数量过大时出现爆栈的情况。

不用担心。异步“递归”(有时也称为伪递归)不会增加调用栈,它很像尾递归。你永远不会得到堆栈溢出异常。

如果 Promise 库实现得合理,这甚至不会增加内存消耗 - 详情请参见使用 JavaScript 递归构建 Promise 链 - 内存考虑


1

一般情况下,如果没有新的语法或库支持,是不行的。

如果您正在使用babel,可以使用ES2018 (:P)异步迭代:

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

在此处阅读更多相关信息

否则,您可以使用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)。 - Galder Zamarreño
@GalderZamarreño 如果你正在使用NodeJS 0.10,那么你如何使用ES2015呢? - Benjamin Gruenbaum
1
此外,答案仍然不变,在ES2015之前没有递归或执行递归的辅助方法是不可能的。 - Benjamin Gruenbaum
抱歉,我有点混淆了,我是指的 ES5 和 Node.js 0.10 版本。 - Galder Zamarreño
那么不行,你必须使用递归或者一个自身使用递归的辅助函数——有效地将你的loop函数提取到一个辅助函数中。 - Benjamin Gruenbaum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接