3

Is there are more readable way to queue a number of asynchronous effects that they are executed synchronously?

var element1 = $('#div1');
var element2 = $('#div2');

$(element2).hide();
$(element1).on('click',function(){   
    $(element1).fadeOut(1000,function(){
        $(element2).fadeIn(1000, function(){
            $(element2).hide();
            alert('hello');
        });
    });
}); 
Elisabeth
  • 20,496
  • 52
  • 200
  • 321

2 Answers2

3

You can prevent the ever-deeper nesting effect if you use a promise-based system.

$.when(
    $(element1).fadeOut(1000)
).then(function () {
    return $(element2).fadeIn(1000);
}).then(function () {
    return $(element2).hide();
}).then(function () {
    return $(element1).fadeIn(1000);
}).then(function () {
    return $(element1).fadeOut(1000);
});

Demo: http://jsfiddle.net/tYhNq/1

You'll notice this makes it very easy to change the order of the animations.

The "trick" is that the $.when() method returns the promise object associated with the first animation, so then you can just chain a bunch of .then() calls, noting that each then() callback should return the result of its animation.

Of course you can directly chain animations on the same element, e.g. .fadeIn(100).fadeOut(100)...

nnnnnn
  • 147,572
  • 30
  • 200
  • 241
  • I would prefer a $.when at the start and remove the .promise like: $.when($(element1).fadeOut(1000)) and so on... thats more clear I think. – Elisabeth May 19 '13 at 22:15
  • You're right. `$.when()` is neater as seen in [this updated fiddle](http://jsfiddle.net/tYhNq/1/). (`.promise()` was just the first way that came to mind.) – nnnnnn May 19 '13 at 23:31
  • Can you please modify your solution with the $.when? then I mark it as answer :) just for the others...nobody need to read comments... – Elisabeth May 20 '13 at 15:19
  • OK, done, with the explanation rephrased a little to (I hope) make sense with the changed code. – nnnnnn May 20 '13 at 21:35
1

This problem is called "callback hell". In NodeJS you have async module option to "escape" from it.

I didn't find a correspondent option in jQuery.

My suggestion is to create one function for every effect, like bellow:

var element1 = $('#div1');
var element2 = $('#div2');

$(element2).hide();

var finished = function () { console.log(":-)"); }
var hide = function () { element2.hide(); finished(); }
var fadeIn = function () { element2.fadeIn(1000, hide); }
var clicked = function () { element1.fadeOut(1000, fadeIn); }

$(element1).on('click', clicked);

JSFIDDLE

Ionică Bizău
  • 109,027
  • 88
  • 289
  • 474