Reputation: 752
I am making multiple ajax requests like this
imgPromises = [];
imgPromise1 = $.ajax({
url: s3Url,
type: "POST",
data: s3FormData,
mimeType: "multipart/form-data",
contentType: false,
cache: false,
processData: false
}).done(function(data, status, formXHR) {
x = formXHR['responseText'].toString();
var uploadedUrl = x.match("<Location>(.*)</Location>")[1];
if ($(this).attr('id').startsWith('inp')) {
if ($(this).attr('id').startsWith('inp')) $('footer').css('background-image', 'url(' + uploadedUrl + ')');
footerBackground = $('footer').css('background');
}
}).fail(function() {
console.log("in ajax fail");
}.bind(this));
imgPromises.push(imgPromise1);
imgPromise2 = $.ajax({
url: s3Url,
type: "POST",
data: s3FormData,
mimeType: "multipart/form-data",
contentType: false,
cache: false,
processData: false
}).done(function(data, status, formXHR) {
x = formXHR['responseText'].toString();
var uploadedUrl = x.match("<Location>(.*)</Location>")[1];
if ($(this).attr('id').startsWith('inp')) {
if ($(this).attr('id').startsWith('inp')) $('footer').css('background-image', 'url(' + uploadedUrl + ')');
footerBackground = $('footer').css('background');
}
}).fail(function() {
console.log("in ajax fail");
}.bind(this));
imgPromises.push(imgPromise2);
Promise.all(imgPromises.then(function() {});
If any of the promise(imgPromise1
or imgPromise2
) fails then it didn't go to Promise.all
.
I want that in every case it should go to Promise.all
.
Upvotes: 0
Views: 976
Reputation: 39360
Depending on the version of jQuery you are using you can use .catch
and return something in catch that the promise will resolve with.
jQuery's version of Promise.all ($.when) will not reject if any of the deferred (is jQuery promise implementation) rejects.
This is only since version 3 since jQuery's deferred before this version did not behave like standardized promises (the promises native to modern browsers).
function makeRequest(num){//returning $.Deferred like $.ajax will
var d = $.Deferred();
setTimeout(() => {
if(num>1){//reject if number passed is higher than 1
d.reject("Rejecting over one");
return;
}
d.resolve(num)
}, 10);
return d.promise();
}
$.when.apply(//jQueries Promise.all need apply to pass array of "promises"
$,
[1,2].map(//map numbers 1 and 2 to deferred 1 will resolve 2 rejects
function(num){
return makeRequest(num)
.catch(//catch rejected deferred
function(error){return "error in:"+num; }//resolve with this
);
}
)
).then(//both deferred (=jQuery promise like) are resolved
function(){
console.log("it is done",[].slice.apply(arguments));
}
)
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
However, you try the same with version 2 of jQuery and it won't work because implementation of deferred/promise is not like standard promises in versions lower than 3. You could convert Deferred to real promise but if you want to support older browsers you need Promise polyfil:
console.log("jQuery version",jQuery.fn.jquery);
function makeRequest(num){//function returning jQuery deferred (could be $.ajax)
var d = $.Deferred();
if(num>1){
//now this will throw an error
throw("Rejecting over one");
}
setTimeout(() => {
d.resolve(num)
}, 10);
return d.promise();
}
Promise.all(
[1,2].map(
function(num){
//convert deferred to real Promise (having catch) if makeRequest throws then promise is rejected
return Promise.resolve().then(()=>makeRequest(num))
.catch(
function(error){return "error in:"+num; }//resolve to error in... string
);
}
)
).then(
function(){
console.log("it is done",[].slice.apply(arguments));
}
)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Upvotes: 0
Reputation: 341
you are using then
in the wrong place.
const Fail = function(error){this.error=error;};//special Fail type value
const isFail = o=>(o&&o.constructor)===Fail;//see if item passed is fail type
const isNotFail = o => !isFail(o);//see if item passed is not fail type
Promise.all(imgPromises
.map(
p=>Promise.resolve(p)/**convert to real promise*/
).map(
p=>p.catch(error=>new Fail(error))//single request failed, resolve with Fail value
)
)
.then(function (responses) {
// successes = responses.filter(isNotFail)
// failed = responses.filter(isFail)
})
.catch(function (err) {
//handle error
});
Upvotes: 1
Reputation: 3596
To wait until all promises finish their tasks (resolve and/or reject) we return
value of catch()
for each promise.
In this case we use .then()
to receive all information.
We can filter both rejected and resolved data using filterInformation
helper function.
Example:
const mockResolvePromise = (message) => {
return new Promise((resolve) => {
resolve(message)
})
}
const mockRejectPromise = (messageError) => {
return new Promise((_, reject) => {
reject(messageError)
})
}
const ajax0 = mockResolvePromise({ nice: 'data' })
const ajax1 = mockRejectPromise('bad error');
const ajax2 = mockRejectPromise('semi bad error');
const ajax3 = mockRejectPromise('super bad error');
const ajax4 = mockResolvePromise({ hello: 'handsome' })
const promises = [ajax0, ajax1, ajax2, ajax3, ajax4];
// Now lets add catch
const promisesWithCatch = promises.map(p => p.catch(e => { return { error: e } }))
const filterInformation = (stuff) => {
return stuff.reduce((prev, current) => {
if (current.error) return {
...prev,
errors: [...prev.errors, current.error]
};
return { ...prev, data: [...prev.data, current] }
}, { errors: [], data: [] })
}
Promise.all(promisesWithCatch)
.then(filterInformation)
.then(data => console.log(data))
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Upvotes: 0