【问题标题】:how to continue with $q.all() when some promises fail当某些承诺失败时如何继续使用 $q.all()
【发布时间】:2016-09-11 20:20:15
【问题描述】:

我有一系列承诺,每个承诺都调用http.get()

var items = ["URL1", "URL2", "URL3"];
var promises = [];
//on each URL in items array, I want to create a promise and call http.get
items.forEach(function(el){
    return promises.push($http.get(el)); 
});
var all = $q.all(promises);
all.then(function success(data){
    console.log(data);
}).catch(function(reason){
    console.log("reason is", reason);
});

我的情况

URL2.get 没有得到解决,它立即触发$q.all 中的catch()。由于此失败,all.then() 永远不会被调用。

我想要什么

即使其中一个承诺被拒绝,我也希望所有承诺继续。

我发现了一个类似的post,但解决方案建议使用另一个名为 Kris Kowal's Q 的 angular 包装。所以我想知道如何在不使用外部包的情况下实现它?

【问题讨论】:

标签: javascript angularjs promise q


【解决方案1】:

一个简单的技巧可能是在返回 null 的 Promise 中添加一个 catch 块,并过滤来自 promise.all 结果的 null 结果,类似于:

let items = ["URL1", "URL2", "URL3"]
  , promises = items.map(url => $http.get(url).catch(e => null))
  , all = $q.all(promises).then(data => data.filter(d => !!d))

all.then(data => {
  // do something with data
}).catch(e => {
  // some error action
})

在 ES5 中也是这样:

var  items = ["URL1", "URL2", "URL3"]
  , promises = items.map(function(url){
     return $http.get(url).catch(function(e){return null})
  })
  , all = $q.all(promises).then(function(data){
    return data.filter(function(d){return !!d}) // filter out empty, null results
  })

all.then(function(data){
  // do something with data
}).catch(function(e){
  // some error action
})

【讨论】:

    【解决方案2】:

    这是.settle() 的 ES6 兼容版本,它允许完成所有承诺,然后您可以查询每个结果以查看它是成功还是失败:

    // ES6 version of settle
    Promise.settle = function(promises) {
        function PromiseInspection(fulfilled, val) {
            return {
                isFulfilled: function() {
                    return fulfilled;
                }, isRejected: function() {
                    return !fulfilled;
                }, isPending: function() {
                    // PromiseInspection objects created here are never pending
                    return false;
                }, value: function() {
                    if (!fulfilled) {
                        throw new Error("Can't call .value() on a promise that is not fulfilled");
                    }
                    return val;
                }, reason: function() {
                    if (fulfilled) {
                        throw new Error("Can't call .reason() on a promise that is fulfilled");
                    }
                    return val;
                }
            };
        }
    
        return Promise.all(promises.map(function(p) {
            // make sure any values or foreign promises are wrapped in a promise
            return Promise.resolve(p).then(function(val) {
                return new PromiseInspection(true, val);
            }, function(err) {
                return new PromiseInspection(false, err);
            });
        }));
    }
    

    这可以像这样适应 Q 库:

    // Q version of settle
    $q.settle = function(promises) {
        function PromiseInspection(fulfilled, val) {
            return {
                isFulfilled: function() {
                    return fulfilled;
                }, isRejected: function() {
                    return !fulfilled;
                }, isPending: function() {
                    // PromiseInspection objects created here are never pending
                    return false;
                }, value: function() {
                    if (!fulfilled) {
                        throw new Error("Can't call .value() on a promise that is not fulfilled");
                    }
                    return val;
                }, reason: function() {
                    if (fulfilled) {
                        throw new Error("Can't call .reason() on a promise that is fulfilled");
                    }
                    return val;
                }
            };
        }
    
        return $q.all(promises.map(function(p) {
            // make sure any values or foreign promises are wrapped in a promise
            return $q(p).then(function(val) {
                return new PromiseInspection(true, val);
            }, function(err) {
                return new PromiseInspection(false, err);
            });
        }));
    }
    

    与您的特定代码一起使用:

    var items = ["URL1", "URL2", "URL3"];
    $q.settle(items.map(function(url) {
        return $http.get(url);
    })).then(function(data){
        data.forEach(function(item) {
           if (item.isFulfilled()) {
               console.log("success: ", item.value());
           } else {
               console.log("fail: ", item.reason());
           }
        });
    });
    

    注意:.settle() 返回一个始终解析,从不拒绝的承诺。这是因为无论你传递了多少个 Promise 都被拒绝,它仍然会解析,但会返回关于你传递的哪些 Promise 被解析或被拒绝的信息。

    【讨论】:

      【解决方案3】:

      我将 $resource 包装在 $q 中,只有解析状态

      var promises = [
           $q(function (resolve) {
              Me.get({params: 12}).$promise.then(function (data) {
                 resolve(data);
              }, function (err) {
                 resolve(err);
              });
           }),
           $q(function (resolve) {
              Me.get({params: 123}).$promise.then(function (data) {
                 resolve(data);
              }, function (err) {
                 resolve(err);
              });
           }),
           $q(function (resolve) {
              Me.get({params: 124}).$promise.then(function (data) {
                 resolve(data);
              }, function (err) {
                 resolve(err);
              });
           })];
      

      然后使用 $q.all 来承诺

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-01-05
        • 1970-01-01
        • 2019-08-20
        • 1970-01-01
        • 2016-03-04
        • 2012-06-28
        • 2016-08-25
        • 1970-01-01
        相关资源
        最近更新 更多