I am refactoring a resource-loading function that used a traditional callback pattern to instead use jQuery Deferreds.
This function takes and array of urls, creates a new Deferred object for each resource, creates a $.when Deferred object to watch them, and returns the promise of the $.when object.
Here’s a simplified version of the method:
theLib = {
getResources : function(paths) {
var deferreds = [];
theLib.isLoading = true;
$.each(paths, function(i, path) {
// do something with the path, either using getScript
// or making a new $.Deferred as needed
deferreds.push(/* the deferred object from above comment */);
});
theLib.currentDeferred = $.when.apply(null,deferreds).always(function() {
theLib.isLoading = false;
});
return theLib.currentDeferred.promise();
};
This works well.
My problem: In the old script, not only would one call theLib.getResources() based on user actions or events, but one would also define a master list of resources that the application will “stream” while the user is not taking any action (i.e. reading an article).
Some of these streamed resources would be the same resources that could be called manually when a user does take action. The script was smart enough not to load a resource twice by keeping track of what was loaded.
It also keeps track of theLib.isLoading. The beginning of that function looked something like this:
getResources : function(paths, callback) {
if (theLib.isLoading) {
settimeout(function() {
theLib.getResources(paths, callback);
}, 100);
}
theLib.isLoading = true;
I can’t do this anymore, because I need to return a promise object.
I know that I can check theLib.currentDeferred.isResolved(). At that point, if it is not resolved: How can I add more deferred objects to the $.when queue that is being watched?
I guess I needed to ask the question to find a solution for myself. Basically I added the following code the beginning of
getResources:if ( ! theLib.currentDeferred.isResolved()) {return $.when(theLib.currentDeferred).always(function() {
theLib.getResources(paths);
}).promise();
}
The above was failing. The correct solution was to pipe the results: