21

I need a bunch of functions to be called in strict order. It's also very important that the next function waits until the previous one has finished.

Right now I'm using chained callbacks:

callMe1(function(){
    callMe2(function(){
        callMe3(function(){

            callMeFinal();

        });
    });
});

This works but seems to be a little ugly.

Any suggestions for a different approach?

ezmilhouse
  • 8,933
  • 7
  • 29
  • 38
  • I'd try to give you a good answer on how to rearrange your code to avoid these situations, but that very simple code sample doesn't really go into why those functions are currently chained like that... – gnarf Mar 08 '11 at 09:05
  • A similar [question](http://stackoverflow.com/questions/2796375/designing-a-fluent-javascript-interface-to-abstract-away-the-asynchronous-nature) that I asked last year – Anurag Mar 08 '11 at 09:10

5 Answers5

32

If you use jQuery, then you can use queue to chain the functions.

$(document)
  .queue(callMe1)
  .queue(callMe2);

where callMeX should be of form:

function callMeX(next) {
    // do stuff
    next();
}
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 20
    Queues are awesome... One suggestion, instead of binding to `$(document)` bind to `$({})` -- that way the functions inside the queue can use `this` to reference that same shared object. – gnarf Mar 08 '11 at 11:22
7

You can implement a "stack" system:

var calls = [];

function executeNext(next) {
    if(calls.length == 0) return;
    var fnc = calls.pop();
    fnc();
    if(next) {
        executeNext(true);
    }
}

/*To call method chain synchronously*/
calls.push(callMe3);
calls.push(callMe2);
calls.push(callMe1);
executeNext(true);

/*To call method chain asynchronously*/
calls.push(callMe3);
calls.push(function(){
    callMe2();
    executeNext(false);
});
calls.push(function(){
    callMe1();
    executeNext(false);
});
The Scrum Meister
  • 29,681
  • 8
  • 66
  • 64
  • guess this would be the best solution if there wasn't such a thing as jquery's queues, appriciate it – ezmilhouse Mar 09 '11 at 21:41
  • @Meister - in the call method chain asynchronously, , how to invoke the callbacks? since there's only push action – jason Jan 08 '13 at 11:33
3

Not sure if this would help you, but there is a great article on using deferreds in jQuery 1.5. It might clean up your chain a bit...

Also, my answer on Can somebody explain jQuery queue to me has some examples of using a queue for ensuring sequential calls.

Community
  • 1
  • 1
gnarf
  • 105,192
  • 25
  • 127
  • 161
0

You might want to pass parameters to the functions, I do not believe you can at the time of this writing. However...

function callMe1(next) {
    console.log(this.x);
    console.log("arguments=");
    console.log(arguments);
    console.log("/funct 1");
    this.x++;
    next();
}
function callMe2(next) {
    console.log(this.x);
    console.log("arguments=");
    console.log(arguments);
    console.log("/funct 2");
    this.x++;
    next();
}
function callMe3(next) {
    console.log(this.x);
    console.log("arguments=");
    console.log(arguments);
    console.log("/funct 3");
    this.x++;
    next();
}
var someObject = ({x:1});
$(someObject).queue(callMe1).queue(callMe2).queue(callMe3);
0

Wrapping your functions, arguments intact, with an anonymous function that plays along with .queue works too.

Passing Arguments in Jquery.Queue()

var logger = function(str, callback){
    console.log(str);
    //anything can go in here, but here's a timer to demonstrate async
    window.setTimeout(callback,1000)
}

$(document)
.queue(function(next){logger("Hi",next);})
.queue(function(next){logger("there,",next);})
.queue(function(next){logger("home",next);})
.queue(function(next){logger("planet!",next);});

Example on JSFiddle: http://jsfiddle.net/rS4y4/

Community
  • 1
  • 1
JosephSlote
  • 316
  • 2
  • 10