我有一个处理程序队列,我需要按插入顺序执行,然后在执行下一行之前等待每个处理程序返回已解析的promise。
我决定使用递归函数将处理程序移出队列然后执行它。当处理程序解析其promise时,函数会递归调用自身,直到队列为空。
var executeHandler = function(handlers, instance){
var handler, cb = function(){
return executeHandler(handlers, instance);
};
if(handlers.length){
handler = handlers.shift();
return handler($q, instance).then(cb);
}
};
这是一个适当的解决方案。但我不确定这是一个理想的解决方案。当单步执行此功能时,很难遵循。
有更优化的方法来实现这一目标吗?更重要的是更易于掌握的解决方案?
答案 0 :(得分:4)
好吧,就像jfriend和Roamer建议的那样 - 你不必实际实现递归,因为promises已经链接了。让我们回顾一下:
.then
表示代码中的分号或行删除,它是流控制和排序本身概念的抽象。它实际上非常接近monad bind。then
s替换分号。 让我们从同步版本开始
function each(handlers, instance){
// here the function flow control starts
handlers.forEach(function(handler){ // iterate all handlers
handler(instance); // call the handler
}); // in the promises version we'll iterate in advance since it's simpler
return; // when the function returns it's done
}
现在,我们如何将其转换为承诺代码?
$q.when
handler()
将“等待前一个处理程序完成,然后运行此程序”。这应该类似于:
function each(handlers, instance){
var p = $q.when();
handlers.forEach(function(handler){
p = p.then(function(){ return handler(instance); });
});
return p;
}
这里的优点是流程是循环而不是递归,这对某些人来说更容易理解,基本上不是实现我们自己的“下一个”逻辑,而是将责任委托给了承诺。以下是reduce
的jfriend和漫游者的意思:
function each(handlers, instance){
return handlers.reduce(function(p, next){
return p.then(function(){ return next(instance); });
}, $q.when());
}
这种事情(将数组聚合成单个值)正是减少的原因,这就是为什么它如此自然地适应。
虽然for循环解决方案可能不容易通过调试器逐步完成,但我认为它比你的第一个解决方案的显式递归和簿记更容易掌握。