如果某些承诺失败,如何继续使用$ q.all()

时间:2016-05-16 05:25:34

标签: javascript angularjs promise q

我有一系列的承诺,每个承诺都会调用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无法解决,会立即触发catch()中的$q.all。由于此失败,all.then()永远不会被调用。

我想要什么

即使其中一项承诺被拒绝,我也希望所有的承诺能够继续下去。

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

3 个答案:

答案 0 :(得分:7)

一个简单的hack可能会向promises添加一个catch块,返回null,并过滤掉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
})

答案 1 :(得分: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()会返回一个始终解析但永不拒绝的承诺。这是因为无论你传递多少承诺拒绝它,它仍然会解决,但会返回你通过它的承诺解决或拒绝的信息。

答案 2 :(得分:0)

我将$资源包装在$ 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来承诺