I have an array queue
that I push objects to it when they are modified. If the user presses save
, then I will loop through the queue
and apply the appropriate API call for them.
If the API call goes through successfully, I want to remove the item from the queue
, otherwise keep it inside and notify the user that some items were not successfully saved. I currently have this (in AngularJS)
var unsuccessfulItems = [];
var promise = queue.map(function(item) {
var defer = $q.defer();
myCallFunction( item
, function( response ) {} // Success
, function( response ) { // Error
unsuccessfulItems.push(item);
}
)
defer.resolve();
return defer.promise;
})
// Once all items have been processed
$q.all( promise ).then( function() {
queue = unsuccessfulItems;
});
Is there a better way of doing this?
To remove elements from ArrayList based on a condition or predicate or filter, use removeIf() method. You can call removeIf() method on the ArrayList, with the predicate (filter) passed as argument. All the elements that satisfy the filter (predicate) will be removed from the ArrayList.
map() is a non-destructive method.
As discussed, map() method always returns a new array, so if you don't have any use of a new array then never use map() method.
shift() function: This method is use to remove elements from the start of an array. splice() function: This method is use to remove elements from the specific index of an array. filter() function: This method is use to remove elements in programmatically way.
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; });
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With