Jonline
Jonline

Reputation: 1747

jQuery: using deferred properly in a local context (ie. no AJAX)

Apologies for what I'm sure is a repost; I really have looked quite widely for an answer to my question (that I also understood).

What I'm trying to learn to do is to arbitrarily chain functions such that they must complete before the next occurs, which, as I understand it, is the purpose of jQuery's deferred(). So in the below code, what I'm imagining should happen is:

  1. the function contained within the load deferred objects executes; after which
  2. the function contained in then() executes; after which
  3. the function contained in done() executes.

Every tutorial in the universe uses a $.ajax() object after $.when(), which is useless if all one wants is control of execution sequence in a local context.

Here's what I've been trying:

var preloadDone = false,
var testDone = false,

var load = $.deferred(function() {
                //cacheImages() is a plugin, works fine
                $("img.image-loader.preload").cacheImages();
                preloadDone = true;
            });

var loader = $.when(load)
        .then(function() {
        if (preloadDone) {
            console.log("then called in sequence");
        } else {
            console.log("then called out of sequence"); // wrong order, every time
        }
        XBS.cache.cbDone = true;
}).done(function() {
        if (XBS.cache.cbDone) {
            console.log("even done was called in right sequence!"); // proper order, every time
        } else {
            console.log("done() wasn't called in order.."); 
        }
});

load.resolve(); // nothing happens
// load();  also tried this; nothing happens

So far as I can tell, this is identical to the example given in the jQuery $.when() documentation. Lil help?

Upvotes: 0

Views: 66

Answers (2)

Tasos
Tasos

Reputation: 5361

Here is a demo on how to run many functions one after another but only after each funtion has completed. This is achieved by using an Async function.

Demo (Runs 3 functions one after the other. Where i have alert("starting *") that is were you want to put the work you like to do and in the done function you include the next function you want to run. )

http://jsfiddle.net/5xLbk91c/

//the Assync function. Pause is the time in miliseconds to pause between loops

var asyncFor = function(params) {

    var defaults = {
      total: 0,
      limit: 1,
      pause: 10,
      context: this
    },
      options = $.extend(defaults, params),
      def = $.Deferred(),
      step = 0,
      done = 0;

    this.loop = function() {
      if (done < options.total) {
        step = 0;
        for (; step < options.limit; step += 1, done += 1) {
          def.notifyWith(options.context, [done]);
        }
        setTimeout.apply(this, [this.loop, options.pause]);
      } else {
        def.resolveWith(options.context);
      }
    };

    setTimeout.apply(this, [this.loop, options.pause]);
    return def;
  };




function one() {

asyncFor({
  total: 1,  // run only once. If you want to loop then increase to desired total. 
  context: this
}).progress(function(step) {

alert("starting one")

}).done(function() {

alert("finished one")

two()

});    

}

function two() {

asyncFor({
  total: 1,
  context: this
}).progress(function(step) {

alert("starting two")

}).done(function() {

alert("finished two")

three()

});    

}

function three() {

asyncFor({
  total: 1,
  context: this
}).progress(function(step) {

alert("starting three")

}).done(function() {

alert("finished three and all done")

});    

}

Upvotes: 1

Wojciech Fornal
Wojciech Fornal

Reputation: 1563

you may want to start your investigations by this change to your code:

var load = function() {
  var deferred = $.Deferred();
  $("img.image-loader.preload").cacheImages();
  preloadDone = true;
  return deferred;
};

Please also note you may pass array of promises to $.when().

Best regards

Upvotes: 0

Related Questions