顺序运行大量的承诺

一个nodejs项目。我试图用承诺顺利运行大量(大约100k)任务。 我可以做的是将其转换为一个workOnebyOne函数与Q.有没有更好的方法来做到这一点?

function workOnebyOne(items, worker) { var deferred = Q.defer() function _doNext() { if (items.length === 0) { deferred.resolve() return } var item = items[0] synchronize(worker, item) .then(function (result) { items = items.slice(1) deferred.notify({ item: item, result: result }) _doNext() }, function () { items = items.slice(1) _doNext() }) } _doNext() return deferred.promise } utils.workOnebyOne(tasks, workerFunction) 

你基本上是在这里重新执行排队。 在蓝鸟承诺(这也是更快,消耗更less的内存,这有助于100K任务),你会使用Promise.each

在Q中,你通常可以在任务数组上使用.reduce来将它们一次排队 – 但是,如果有100K个元素在Q promise中创build一个100K的promise队列,就会导致节点崩溃(同样,Q,Bluebird或Promise) )。 这个(不正确的)解决scheme看起来像这样:

 var res = tasks.reduce(function(p, c){ return p.then(function(){ return workerFunction(c); }); }, Q()); 

对于短排队(Q中<500个承诺),这很好地工作。

所以,由于旧图书馆的select,并且由于涉及到大量的承诺,你不能现实地解决它的优雅,所以使用类似callback的方法是非常接近你的唯一方法。 我也避免notify因为它被删除(甚至从Q),通常是一个糟糕的API(不好)。

我花了一些时间寻找简单而优雅的解决scheme。 我发现只有一些提示和讨论,但没有现成的例子。 最后,我在https://github.com/kriskowal/q/issues/606上发现了一些讨论,结果是,对我而言可以被隔离和泛化的是&#xFF1A;

 function workOneByOne(items, someAsyncFuntionReturningPromise) { var lastResultPromise = items .map(function(item) { return function(previousResult) { /* * this function has to: * - process result from previous item processed if any * - call the async job * - return promise of the job done */ if (previousResult) { // process result here } return someAsyncFuntionReturningPromise(item); }}) .reduce(Q.when, Q()); return lastResultPromise; } 

如果没有函数返回承诺可用,你可以在上面调用

 workOneByOne(items, Q.nfbind(someAsyncFunctionWithCallback))