一个nodejs项目。我曾尝试使用promises执行大量(约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 :(得分:2)
您基本上是在这里重新实施排队。在Bluebird的承诺中(你也可以使用Promise.each
,速度更快,内存消耗更少,有助于100K任务)。
在Q中你通常可以在tasks数组上使用.reduce
来立即对它们进行排队 - 但是在Q promises中创建100K承诺队列的100K元素会崩溃节点(再次,这是Q,Bluebird或承诺时) )会处理它就好了)。这个(这里不正确)解决方案看起来像:
var res = tasks.reduce(function(p, c){
return p.then(function(){ return workerFunction(c); });
}, Q());
对于短队列(Q中的< 500 promises),这很有效。
因此,由于旧的库选择,并且由于涉及大量的承诺,您无法优雅地实际解决它,使用类似方法的回调队列非常接近您的唯一方式。我也避免notify
因为它被移除(即使是Q),并且通常是一个糟糕的API(不能很好地构成)。
答案 1 :(得分: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))
答案 2 :(得分:1)
如果await / async
可用,则为超简单解决方案。
// functions is an array of functions that return a promise.
async function runInSequence(functions) {
const results = [];
for (const fn of functions) {
results.push(await fn());
}
return results;
}
我们可以像这样使用它:
/**
* Waits "delay" miliseconds before resolving the promise.
* @param {Number} delay The time it takes to resolve the promise.
* @param {any} value The resolving value.
*/
function promisedFunction(delay, value) {
return new Promise(resolve => {
setTimeout(() => resolve(value), delay);
});
}
console.time("execution");
runInSequence([
promisedFunction.bind(this, 1000, 1),
promisedFunction.bind(this, 1000, 2),
promisedFunction.bind(this, 1000, 3)
]).then(results => {
console.timeEnd("execution");
console.log(results);
});
有效的RunKit示例here。