shenkwen
shenkwen

Reputation: 3880

Mechanism of Recursive Callbacks

See this fiddle: http://jsfiddle.net/ym1aLk25/9/

var s = $('#shake');
var randomTran = function (flag) {
    flag = flag || 0;
    if (flag < 6) {
        var rh = Math.floor((Math.random() * 10) - 5),
            rv = Math.floor((Math.random() * 10) - 5);
        s.transit({x: rh,y: rv}, 50, randomTran.bind(this, ++flag))
    };
};
randomTran();
s.transit({x: 0,y: 0});

I'm trying to make the element shake for a few seconds and then return to its original position. But it doesn't work as I expected, the problem is with the callback function. According to this question: If a jQuery function calls itself in its completion callback, is that a recursive danger to the stack?, it seems that while callback is still looping, the codes that come after the callback function are also being executed. So how to achieve my goal, other than setting a timeout? And where can I find a more detailed explanation about this mechanism?

Upvotes: 0

Views: 61

Answers (2)

Bergi
Bergi

Reputation: 664640

Your fiddle is working as expected, and the animations are queued (they even would be queued if .transit() was called multiple times repeatedly, as the plugin uses jQuery's internal animation queue). The only thing is that 50 milliseconds for a animation on up to 5 pixels are much too fast. I've increased the time and printed the counter in this revision of your fiddle.

it seems that while callback is still looping, the codes that come after the callback function are also being executed.

There is no "looping callback". The callback is passed to the function which returns before the callback is called - and the code that called .transit() continues (which, in your case, is the closing } brace from the if, the end of the randomTran() call, and the s.transit({x: 0,y: 0}); initialisation.

Once this code has finished executing, other code can be executed - asynchronously. The callback that was stored somewhere is now - in the future, 50ms after the transit() call - being called; does start another transition, does schedule another callback, and ends.

Upvotes: 1

xShirase
xShirase

Reputation: 12399

There is no callback in your randomTran function, so it runs asynchronously. This means that randomtran() starts, and just after, s.transit({x: 0,y: 0}); is executed.

You could run s.transit({x: 0,y: 0}); in the callback of randomTran to have it execute after the rest like so :

var s = $('#shake');
var randomTran = function (flag,callback) {
    flag = flag || 0;
    if (flag < 6) {
        var rh = Math.floor((Math.random() * 10) - 5),
            rv = Math.floor((Math.random() * 10) - 5);
        s.transit({x: rh,y: rv}, 50, randomTran.bind(this, ++flag))
    }else{
      callback();
    }
};
randomTran(0,function(){ //0 is added because randomTran expects flag as first param
  s.transit({x: 0,y: 0}); //this will be executed after randomtran calls back, eg when flag=6
});

but... I'm afraid you're overcomplicating things and I'm not really sure what you want to achieve.

Upvotes: 0

Related Questions