javascript - 在node.js中迭代大量异步调用/结果(使用ES6/async/bluebird/generators)?

标签 javascript node.js promise bluebird node-async

我正在用 node.js 编写一个实用程序,它必须每天晚上处理和连接大量文件。在同步伪代码中,它看起来像这样(为了清楚起见,省略了 try/catch):

while (true) {
    var next = db.popNext();
    if (!next) return;

    out.append(next);
}

但是,在我使用的库中 popNext() 实际上是一个 Node 样式的异步方法,看起来像这样:popNext(callback)

由于我是从头开始编写中间件,因此我可以使用 --harmony (例如 generators )、 asyncbluebird .

理想情况下,我更喜欢这样的东西:

forEachOrdered(db.popNext, (error, next, ok, fail) => {
   if(error) return; // skip

   // If there was an internal error, terminate the whole loop.
   if(out.append(next)) ok();
   else fail();
}).then(() => {
   // All went fine.
}).catch(e => {
   // Fail was called.
});

但是,我对其他“标准”解决方案持开放态度。我想知道这个问题最简洁的解决方案是什么?

编辑仅同时生成所有内容(在常规 for 循环中)可能无法解决我的问题,因为我们正在谈论 100k,并且对于每个项目我都必须打开并读取一个文件,所以我可能会用完文件描述符。

最佳答案

这是一个使用 bluebird 协程的解决方案,使用您的“理想”代码:

var db = Promise.promisifyAll(db);

var processAll = Promise.coroutine(function*(){
  while(true){
    var next = yield db.popNextAsync(); // promisify gives Async suffix
    if(!next) return;
    out.append(next); // some processing
  }       
});

在 ES2016 (ES7) 中,这变为:

var db = Promise.promisifyAll(db); // still need to promisify

async function processAll(){
  let next;
  while(next = await db.popNextAsync()){
     // whatever
     out.append(next);
  }
}

尽管如此,我认为输出集合也应该是可迭代的(并且是惰性的),因此使用 ES2016 异步迭代器:

var db = Promise.promisifyAll(db);
async function* process(){
    while(true){
       var val = await db.popNextAsync();
       if(!val) return;
       // process val;
       yield process(val); // yield it forward
    }
}

尽管如果我们真的想要全力以赴,那么在将 db.popNext 转换为异步迭代器之后,这将成为 ES2016 异步表示法:

async function* processAll(){
    for async(let next of db.asAsyncIterator()){ // need to write this like above
       yield process(next); // do some processing
    }
}

利用整个 ES2016 异步迭代 API。如果您不能或不想使用生成器,您始终可以将 while 循环转换为递归:

function processAll(){ // works on netscape 7
   return db.popNextAsync().then(function next(value){
      if(!value) return;
      out.push(process(value));
      return db.popNextAsync().then(next); // after bluebird promisify
   });
}

关于javascript - 在node.js中迭代大量异步调用/结果(使用ES6/async/bluebird/generators)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31367678/

相关文章:

javascript - 通过 JavaScript 连接到计算机音频源

javascript - visjs 加载图表完成后获取回调

javascript - 如何在 mongodb 模式中使用预定义值创建字段,并让用户使用单选按钮选择值

javascript - AngularJS:forEach http 获取数据 - 等待其他方法,直到加载循环中的所有数据

javascript - 将嵌套的 'for' 循环转换为 Promise,对于 Promise?嵌套 promise ?

javascript - 在自定义 promise 上使用异步等待

javascript - Leaflet JS (react-leaflet) - 填充透明颜色的边界框

javascript - 如何为循环创建数组

node.js - oracledb npm 包安装失败

node.js - Nodejs setNoDelay() 不起作用。是否有刷新套接字缓冲区的替代方案?