Reputation: 701
I'm trying to make loop of ajax calls from an array and saving each data result that I'll print when all calls are successfully received.
The problem is that if there is any ajax call returning error, the whole process is aborted and the callback is not executed. (Try using listWithErrorResult)
How to push something on error without breaking the loop?
var list = ['UQ13nr6urIo', 'hxa_Z0eZ83E', 'ulHB2mNlovg'];
var listWithErrorResult = ['UQ13nr6urIo', 'hxa_Z0eZ83E', 'IWEHeIdBkc4'];
var callback = function() {
console.log("done");
console.log(tracks);
};
var requests = [], tracks = [];
for(i = 0; i < list.length; i++) {
requests.push($.ajax({
url: 'http://www.youtubeinmp3.com/fetch/?format=JSON&video=https://www.youtube.com/watch?v='+list[i],
dataType: "json",
success: function(data) {
console.log('suc');
tracks.push(data);
},error: function() {
console.log('err');
tracks.push('err');
}
}));
}
$.when.apply(undefined, requests).then(function(results){callback()});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Upvotes: 0
Views: 922
Reputation: 707158
You can just attach a .then()
handle to your ajax call and make sure every ajax call resolves rather than rejects. This will get you an array of results at the end that is guaranteed to include all your ajax calls.:
var callback = function(/* tracks are passed here as arguments */) {
console.log("done");
var tracks = Array.prototype.slice.call(arguments);
console.log(tracks);
};
var requests = [];
for(var i = 0; i < list.length; i++) {
requests.push($.ajax({
url: 'http://www.youtubeinmp3.com/fetch/?format=JSON&video=https://www.youtube.com/watch?v='+list[i],
dataType: "json",
}).then(function(data) {
return data;
}, function(err) {
// convert failure into success so $.when() doesn't stop
return $.Deferred().resolve('err');
}));
}
$.when.apply($, requests).then(callback);
You can also use a version of $.settle()
that I wrote that lets all promises finish and gives you all results, even if some promises reject.
Instead of $.when()
(which stops on the first rejected promise), you can use this new function $.settle()
which returns you the results of all the promises. It returns an array of PromiseInspection objects which allow you to query the resolved value or rejected reason for each promise.
You use $.settle()
just like $.when()
except it returns all results in PromiseInspection objects and it always resolves (never rejects). Because of jQuery's non-standard means of passing multiple arguments to .then()
handlers (particular Ajax calls), if .settle()
detects multiple arguments, it copies them into an array so the PromiseInspection.value returned from a successful ajax call is an array [data, textStatus, jqXHR]
. This is the worst part of jQuery's non-standard promises. Presumably this is fixed/changed in jQuery 3.x which is supposed to be standard's compliant. This code will work with either since it auto-detects if the .then()
handler is sent more than one argument and converts them into a single array argument.
// ES6 version of settle
jQuery.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 $.when.apply($, promises.map(function(p) {
return p.then(function(val) {
if (arguments.length > 1) {
val = Array.prototype.slice.call(arguments);
}
return new PromiseInspection(true, val);
}, function(err) {
if (arguments.length > 1) {
err = Array.prototype.slice.call(arguments);
}
return new PromiseInspection(false, err);
});
}));
}
Upvotes: 1
Reputation: 731
You have to add error callback to $.when.apply
then
too as its an error condition when one of the call fails.
$.when.apply(undefined, requests).then(
function(results){callback()},
function(results){callback()}
);
Working jsBin here
Upvotes: 1