将回调转换为承诺

时间:2014-05-16 05:32:32

标签: angularjs promise

我以两种不同的方式向服务器询问一条信息。没有承诺,它可以如下工作

function callback(someData) {
    displaySomeData();
}

request1(user.name, callback);
request2(user.id, callback);

两个请求都可能返回所需的信息 1 ,其中一个或两个可能没有结果。 callback正确处理缺失的信息。

实际上,这两个请求可以简单地汇总到一个像

这样的单一请求中
aggregateRequest(user, callback) {
    request1(user.name, callback);
    request2(user.id, callback);
}

我很好奇这是如何用承诺书写的。

我知道有一个$q.all(promises)会在完成所有承诺时调用其then参数。我想我需要像$q.each这样的东西,每当一个承诺得到满足时就会调用它的参数。

这个案例中使用promises是一个愚蠢的想法......但是混合使用承诺和回调会觉得很糟糕。


1 我们可以争辩说,如果第一个成功,它会按顺序保存请求。我们也可以争辩说,将两个请求结合起来会更有效率。但是现在让我们忘记它。

修改

理想情况下,我想对两个请求做出反应,因为每个请求都可能返回值得合并的不同部分数据。我真的必须两次调用then部分而且我害怕,这不是承诺的设计目的。

我可能会去all。或者也许是Benjamin Gruenbaum any的修改版本,只有在它足够好的情况下才会返回第一个结果(否则等待第二个结果并合并它们)。

2 个答案:

答案 0 :(得分:2)

根据docs所有你需要处理的是all(),这听起来不像你想要的那样。据我所知,你会被困在

request1(user.name).then(displaySomeData);
request2(user.id).then(displaySomeData);

我个人更喜欢回调方法。

答案 1 :(得分:1)

$q中没有内置方式来编写.any方法,该方法可以使用多个方法中的一个方法解析。但是,写一个很简单。

function any(){
    var rejected = 0;
    var d = $q.defer();
    for(var i = 0; i < arguments.length; i++){
         arguments[i].then(function(val){ d.resolve(val); }).catch(function(el){
              rejected++;
              if(rejected == arguments.length) d.reject(new Error("All promises rejected"));
         });
    }
    return d.promise();
}

any(promise1,promise2).then(function(value){
      // access the value of the resolved promise (first one) here.
}).catch(function(err){
      // error caught here if the above .then threw, or if all promises rejected
});

这是有效的,因为promise是一次性操作的抽象,只能解析一次。

还原为回调。回调不是安全的,并且有错误处理问题,当你在多个图层中混合回调和承诺时,你就输了。

Promise是对多个事件触发概念的抽象,你需要它 - 一个事件发射器模式。承诺一旦解决就不会改变状态。

function each(promises, progressHandler){
    return $q.all(promises.map(function(promise){
        return promise.then(function(val){ progressHandler(val); return val; }); 
    }));
}

这类似于$q.all,除了它通过简单的事件发射器(如接口)通知您进度不属于承诺的一部分。用法是

 each([p1,p2,p3],function(val){
     // change progress bar width or notify data
 }).then(function(values){
     // here, all promises resolved
 });

请注意,您也可以使用$q内置notify进度系统,但我相信,以及我在承诺社区中与之交谈的大多数人的信念,承诺通知是破碎了,将来可能会更换,所以我不会依赖它。