Reputation: 4339
My application has a bunch of $.ajax
calls that mostly have .done
and .fail
functions.
I want to write a wrapper around the Ajax call, so that if a function does not have a .fail
function, or if the .fail
function does not handle a given error (for example it only handles 404, but I get back a 403), then I want the wrapper to handle it as a fallback.
Here's what I've written:
function DoAjax(fn, errorText) {
var deferred = $.Deferred();
var result = fn();
if (result === undefined)
throw 'Function passed into DoAjax has not returned a promise.';
result.always(function () {
deferred.resolve(result);
});
result.fail(function () {
alert('fail');
deferred.fail();
});
return deferred.promise();
}
It works mostly as I intend, except that the fail will execute twice - once in the method DoAjax, the other at the site of the Ajax call.
I execute DoAjax
like this:
DoAjax(function () {
var ajaxCall = $.ajax({
method: "GET",
url: baseUrl + "api/test"
});
ajaxCall.fail(function() { alert('failed the call'); });
return ajaxCall;
});
I believe I can probably accomplish this by manually creating a $.deferred and then doing the $.ajax call around that, but would rather not have another wrapper around it.
I'm using jQuery 2.2.
Upvotes: 1
Views: 130
Reputation: 19288
It's time to do some hard-core learning. Several things need to be taken on board :
.done()
and .fail()
are just jQuery.ajax()
options without the socalled "filtering power" of .then(successCallback, errorCallback)
(or .then()
/.catch()
in jQuery 3+). In other words, whatever is returned from .done()
and .fail()
callbacks has no downstream effect on a jqxhr promise chain.fn()
, in this case, returns jqxhr
, not a result. Therefore, as written, the if(result === undefined)
test will always return false
. The result that the jqxhr eventually delivers can't be tested in this way.jQuery.when(...)
, eg $.when(fn())
.jQuery.when(...)
. There's no need for an explicit $.Deferred()
.Try this :
var baseUrl = '/';
function DoAjax(fn) {
return $.when(fn()) // no need to test for fn() not returning a promise. `$.when(fn())` forces any non-Promise to Promise.
.then(function(response) {
console.log('success!', response);
}).then(null, function(err) {
console.error('B', err); // (LOG_2)
});
}
DoAjax(function () {
return $.ajax({
method: "GET",
url: baseUrl + "api/test"
}).then(null, function(jqxhr, textStatus) {
var err = new Error('Whoops! ' + jqxhr.status + ': ' + textStatus);
console.error('A', err);
// "throw behaviour"
return err; // propagate the error (jQuery <3) or `throw err;` (jQuery 3+)
// "catch behaviour"
// return $.when('default response'); // "2" mutate failure into success (jQuery <3) or `return 'default response';` (jQuery 3+)
});
});
Now try swapping out the lines labelled "propagate behaviour" and "catch behaviour" and observe the difference in the log.
Don't worry if you don't get it immediately. Learning this stuff takes time.
If you have a choice, then work jQuery 3+, in which jqxhr and other Promises are far closer to javascript's native Promise
than in jQuery <3.
Upvotes: 2