I have an existing project that has a lot of asynchronous functions that return promises. I\'m adding some caching so that in some cases the asynchronous functions will complet
@Eselk,
In my experience, the $.Deferred(function(def) {...});
construction is rarely needed, though I guess it can be quite useful in some circumstances.
Firstly, :
return $.Deferred(function(def) { def.resolve(); }).promise();
will simplify to :
return $.Deferred().resolve().promise();
Secondly, in DataService.makeRequest()
you can avoid the need for an explicit $.Deferred
by exploiting .then()
, as follows :
function DataService() {
var self = this;
self.makeRequest = function (functionName, data) {
return $.ajax({
type: "POST",
url: "WebService.asmx/" + functionName,
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
dataType: "json"
}).then(null, function (xhr, status, error) {
var ex;
try {
ex = eval("(" + xhr.responseText + ")");
ex.message = ex.Message;
ex.Message = undefined;
} catch (ex2) {
ex = {
message: "Invalid Response From Server:\r\n" + xhr.responseText
};
}
if (ex.message == "LoginRequired") {
app.viewModels.main.loginRequired(true);
} else {
app.showError(ex.message);
}
return ex.message;
});
};
}
The key aspects here are :
$.ajax()
returns a promise-compatible jqXHR object, which (on success/error) is immediately acted upon and modified by .then()
..then(null, ...)
- causes a new promise to be passed on, resolved with the same values as the original promise returned by $.ajax()
. Thus, under the 'done' (ie ajax success) condition, .then()
is completely transparent.return ex.message;
- causes a new promise to be passed on, rejected with ex.message
.The nett effect should be identical to your original code though, IMHO, chaining .then()
is significantly cleaner than setting everything up inside a $.Deferred()
callback.
By the way, you may be able to avoid the need for eval("(" + xhr.responseText + ")")
etc by setting an appropriate HTTP header server-side such that your '.Message' appears directly as the status
argument (or xhr.status
?) of the fail callback. For example, in PHP you would do something like :
$message = "my custom message";
header("HTTP/1.1 421 $message");
exit(0);
I'm sure ASP offers the same capability.
IIRC, any 4xx series status code will do the job. 421 just happens to be one without a specific meaning.
Simply use return $.when();
to return an already resolved promise.
If you don't pass it any arguments at all, jQuery.when() will return a resolved promise.
Reference: https://api.jquery.com/jquery.when/
Notes:
return $.when(undefined);
which leads to the following rather cool trick which avoids any use of arrays and apply
.If you want to wait for a variable number of promises to complete in parallel then you can use this pattern in a loop:
var promise; // Undefined is treated as an initial resolved promise by $.when
while (insomeloop){
promise = $.when(promise, newpromise);
}
then make a final call on completion with:
promise.then(function(){
// All done!
});
e.g.
var promise;$.when
var $elements = $('.some-elements');
$elements.each(function(){
var $element = $(this).fadeout();
promise = $.when(promise, $element.promise());
});
promise.then(function(){
// All promises completed!
});
The downsides are minor:
when
wraps the previous promise in a new promise. A minor overhead and you no longer need to maintain and evaluate an array of promises.