Reputation: 2549
I have an array of promises and each promise calls 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);
});
what's happening in my case
URL2.get
does not get resolved, and it immediately triggers the catch()
in the $q.all
. As a result of this failure all.then()
never gets invoked.
what I want
I want all the promises to continue even if one of the promise is rejected.
I found a similar post but the solution suggests to use another angular pacakage called Kris Kowal's Q. so I'm wondering how can I achieve it without using external package?
Upvotes: 4
Views: 5867
Reputation: 21
i wrapped the $resource in $q with only resolve state
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);
});
})];
and then use $q.all to promises
Upvotes: 1
Reputation: 707536
Here's an ES6 compatible version of .settle()
which allows all promises to finish and you can then query each result to see if it succeeded or failed:
// 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);
});
}));
}
This can be adapted for the Q library like this:
// 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);
});
}));
}
Usage with your particular code:
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());
}
});
});
Note: .settle()
returns a promise that always resolves, never rejects. This is because no matter how many promises you pass it reject, it still resolves, but returns the info on which promises you passed it resolves or rejected.
Upvotes: 3
Reputation: 25034
a simple hack might be adding a catch block to promises that return null, and filtering the null results from you promise.all
result, something like:
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
})
same thing in 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
})
Upvotes: 9