Run jQuery each() serially
by Ashish DattajQuery.each() is pretty sweet but earlier today I wanted to run some animations across a set of three elements and since the animate() calls are non-blocking everything was happening at the same time. What I wanted to do was have the functions execute in a serial fashion (1 after the other).
I poked around and it doesn’t look like there’s a native way to do this. After a bit I decided to just whip something up and see how it works. Here’s what I had originally:
$("#splashStream .snippetbox").each( function(index){
$(this).animate( {opacity: 0}, 1000, function(){
$(this).html( $("#hiddenSplashDiv .snippetbox:eq(" + index + ")").html() );
$(this).animate( {opacity: 1}, 2000 );
});
});
That ran fine but everything happened at the same time. The modified serial code looks like:
var hasCallbackCompleted = [ true ];
$("#splashStream .snippetbox").each( function(index){
var f = arguments.callee;
var args = arguments;
var t = this;
if( !hasCallbackCompleted[ index ] ){
window.setTimeout( function(){ f.apply(t, args); }, 5 );
return true;
}
hasCallbackCompleted[ index + 1 ] = false;
$(this).animate( {opacity: 0}, 1000, function(){
$(this).html( $("#hiddenSplashDiv .snippetbox:eq(" + index + ")").html() );
$(this).animate( {opacity: 1}, 2000, function(){
hasCallbackCompleted[ index + 1 ] = true;
});
});
});
Basically, what it does is after the first element, the code will delay execution of the each() function until the hasCallbackCompleted flag is set for the correct element.

July 20th, 2010 at 5:51 pm
You can also just put a $(this).delay(index*500).animate({Blah}); in there. Not the most appropriate way if you are handling lots of items, but for a small amount it works great.
July 21st, 2010 at 8:40 am
oh good call. didn’t think of that at all. thanks for the tip.