迭代Promise迭代器的非递归方法

Non-recursive method to iterate over Promise iterator

本文关键字:递归方法 迭代器 Promise 迭代      更新时间:2023-11-26

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

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

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

现在,假设用户想要遍历所有元素,直到next()返回的Promise返回包含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

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

不要害怕。异步"递归"(有时称为伪递归)不会增加调用堆栈,它很像尾部递归。你永远不会得到一个stackoverflow例外。

如果promise库得到了合理的实现,这甚至不应该增加内存——有关详细信息,请参阅在javascript中递归构建promise链。

没有新语法或库-通常没有

好吧,如果你使用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
}