执行返回promise的处理程序队列

时间:2014-08-22 23:24:39

标签: javascript angularjs recursion promise

我有一个处理程序队列,我需要按插入顺序执行,然后在执行下一行之前等待每个处理程序返回已解析的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);
    }
};

这是一个适当的解决方案。但我不确定这是一个理想的解决方案。当单步执行此功能时,很难遵循。

有更优化的方法来实现这一目标吗?更重要的是更易于掌握的解决方案?

1 个答案:

答案 0 :(得分:4)

好吧,就像jfriendRoamer建议的那样 - 你不必实际实现递归,因为promises已经链接了。让我们回顾一下:

  • 承诺代表操作的最终价值。
  • .then表示代码中的分号或行删除,它是流控制和排序本身概念的抽象。它实际上非常接近monad bind
  • 因此,当我们将流控制转换为promises时,我们用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
  • forEach循环是相同的,但我们将同步迭代数组和链函数执行,因为在这种情况下它更简单。
  • 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循环解决方案可能不容易通过调试器逐步完成,但我认为它比你的第一个解决方案的显式递归和簿记更容易掌握。