Reputation: 6186
I have a lot of functions that currently look like this:
function LoadFromURL(url)
{
var d = $.Deferred();
$.get(url).then(function(text)
{
LoadFromText(text).then(function(obj)
{
d.resolve(obj);
},
function(err)
{
d.reject(err);
});
},
function(err)
{
d.reject(err);
});
return d.promise();
}
This function takes a URL and loads the text within a promise. The text is then passed to the LoadFromText function which returns another promise. If this succeeds, the outer deferred is resolved. If the URL cannot be loaded, or the LoadFromText function fails then the outer deferred is rejected.
Is there a way that I can chain the result of the resolve / reject and end up with something like this:
function LoadFromURL(url)
{
return $.get(url).then(function(text)
{
return LoadFromText(text);
},
function(err)
{
return $.Deferred().reject(err);
}).promise();
}
I've seen some implementations of promises that allow this - returning a promise within 'then', means that the eventual result of the promise is used.
I realise this doesn't work at the moment (the result is the promise, rather than the result of the promise), but hopefully someone can suggest a way to make this work so I can tidy up the sometimes confusing mess of the first example.
I hope this makes sense. Thanks.
Upvotes: 1
Views: 203
Reputation: 664444
Is there a way that I can chain the result
Yes, that is the default behaviour of then
!
function LoadFromURL(url) {
return $.get(url).then(LoadFromText);
}
I've seen some implementations of promises that allow this - returning a promise within 'then', means that the eventual result of the promise is used.
jQuery does support this behaviour since version 1.8. For 1.5 to 1.7 you could use .pipe
.
Upvotes: 1
Reputation: 3955
I'm not sure if I understand you correctly, because your second function LoadFromText
is some sort of black box for me. I think, though, that your construct is too bloated for the things executed. Try do do it in more functions that do less. I've done a proposition:
function Load() {
var myUrl = '//path.to/url';
LoadFromUrl(myUrl)
.then(LoadFromText, errorHandler)
.then(successHandler, errorHandler);
}
function successHandler(returnedData) {
console.log('Requests were successful: ' + returnedData);
}
function errorHandler(err) {
console.log('An error occurded: ' + err);
}
function LoadFromURL(url) {
return $.get(url);
}
function LoadFromText(text) {
// THIS IS SOME SORT OF BLACK BOX FOR ME...
// SEEMS TO RETURN A PROMISE, THOUGH
var $deferred = $.Deferred();
// DO THE LOGIC TO EITHER REJECT OR RESOLVE THE PROMISE
return $deferred.promise();
}
You only use the main function Load
to start the ajax chain. As soon as the first ajax request is done, the second starts with the data of the first one. After that, the successHandler will do whatever is needed with the data of the second ajax call. This is the important addition to your solution.
Apart from that it's basically the same thing you did, but distributed to smaller functions that are easier maintainable.
Upvotes: 0
Reputation: 18078
LoadFromURL
will simplify as follows:
function LoadFromURL(url) {
return $.get(url).then(function(text) {
return LoadFromText(text);
});
}
There may be issues you haven't considered ...
Like your original version, the process will tend to recurse indefinitely until the server returns an HTTP error. You would have a slight challenge in writing the server resource appropriately, especially if, as is probable, you need to access the finally delivered text.
With a little more thought, you could deliver all text in such a way that "continue" or "complete" is indicated in the text itself, or in an HTTP response code. For example, you could use response code 202 ("Accepted") to indicate that the process is incomplete.
I think this will work (with jQuery 1.5+) :
function LoadFromURL(url) {
return $.get(url).then(function(text, textStatus, jqXHR) {
if(jqXHR.status === 202) {//continue
return LoadFromText(text);
}
else {//complete
return text;
}
});
}
You just need to arrange for the server to return 202 for "continue" or 200 for "complete".
Thus, LoadFromURL() could be called as follows :
LoadFromURL('my/resource').then(function(text) {
console.log("After a series of $.get requests, the finally delivered text was:\n" + text);
});
Upvotes: 0