2014-12-05 102 views
1

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

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) 
+0

使用索引而不是切片数组可能会更有效。 – 2014-12-05 16:02:19

+1

你的分号钥匙坏了吗? – jfriend00 2014-12-05 18:43:03

+0

'synchronize()'做了什么? – Bergi 2014-12-13 12:44:14

回答

2

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

在Q中,您通常可以在任务数组上使用.reduce将它们一次排队 - 然而,使用100K元素在Q promise中创建100K承诺队列会导致节点崩溃(同样,这是Q,蓝鸟或承诺时)它就好)。这(这里不正确)解决方案看起来是这样的:

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

对于短队列(< 500许诺Q)这工作得很好。

因此,由于旧的图书馆的选择,并且由于涉及大量的承诺,您不能现实地解决它的优雅,使用类似回调队列的方法非常接近您唯一的方式。我也避免notify,因为它被删除(甚至从Q),并且通常是一个糟糕的API(编写不好)。

+0

只是好奇,究竟是什么崩溃Q有很长的承诺序列?你在手边有问题的链接? – Bergi 2014-12-13 12:47:37

+0

这很简单 - Bluebird也会发生同样的情况(尽管承诺数量更多,甚至更多的功能(更高的门槛)),它只消耗太多内存。内存比蓝鸟承诺使用位标志的状态 – 2014-12-13 12:50:23

+0

啊,我认为它会受到调用堆栈或类似的限制 – Bergi 2014-12-14 11:00:11

1

我花了一些时间寻找简单而优雅的解决方案。我发现只有一些提示和讨论,但没有现成的例子。最后,我发现在https://github.com/kriskowal/q/issues/606,结果什么都为我工作可以分离和推广这样的讨论:

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)) 
+0

呃,那不应该是'someAsyncFunctionWithCallback'。为什么不'someAsyncFuntionReturningPromises'? – Bergi 2015-03-10 14:03:58

+0

有时候它可能是一些没有任何承诺的外部功能。例如,我的具体情况是,我最初使用节点http请求,它们不是承诺。然后我转向q-io,所以可以按照您的建议返回承诺。但为了防止上面提出的解决方案考虑到'someAsyncFunctionWithCallback'的cas;) – ciekawy 2015-03-10 14:54:40

+1

这种情况应该由['Q.nfbind']解决(https://github.com/kriskowal/q/wiki/API-Reference #qnfbindnodefunc-args)。 – Bergi 2015-03-10 14:57:50