You're already using promises, you might want to do it end-to-end. Also, you're resolving the promise too early.
Assuming the suboptimal case where you don't want to promisify myCallFunction
itself, you should still promisify it.
function myCall(item){
var d = $q.defer();
myCallFunction(item,function(r){ d.resolve({val:r,item:item});}
,function(r){ d.reject(r);});
return d.promise;
}
Note, we are resolving the defer after the asynchronous function is done, not before it.
Now, we need to implement a "Settle" function, that resolves when all promises are done no matter what. This is like $q.all
but will wait for all promises to resolve and not fulfill.
function settle(promises){
var d = $q.defer();
var counter = 0;
var results = Array(promises.length);
promises.forEach(function(p,i){
p.then(function(v){ // add as fulfilled
results[i] = {state:"fulfilled", promise : p, value: v};
}).catch(function(r){ // add as rejected
results[i] = {state:"rejected", promise : p, reason: r};
}).finally(function(){ // when any promises resolved or failed
counter++; // notify the counter
if (counter === promises.length) {
d.resolve(results); // resolve the deferred.
}
});
});
}
This sort of settle function exists in most promise implementations but not in $q
. We could have also done this with rejections and $q.all
, but that would mean exceptions for flow control which is a bad practice.
Now, we can settle
:
settle(queue.map(myCall)).then(function(results){
var failed = results.filter(function(r){ return r.state === "rejected"; });
var failedItems = failed.map(function(i){ return i.value.item; });
});
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…