Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wait till a Function with animations is finished until running another Function

I'm having an issue with normal (non-ajax) functions that involve lots of animations within each of them. Currently I simply have a setTimeout between functions, but this isn't perfect since no browsers / computers are the same.

Additional Note: They both have separate animations/etc that collide.

I can't simply put one in the callback function of another

// multiple dom animations / etc FunctionOne();  // What I -was- doing to wait till running the next function filled // with animations, etc  setTimeout(function () {      FunctionTwo(); // other dom animations (some triggering on previous ones) }, 1000);  

Is there anyway in js/jQuery to have:

// Pseudo-code -do FunctionOne() -when finished :: run -> FunctionTwo() 

I know about $.when() & $.done(), but those are for AJAX...


  • MY UPDATED SOLUTION

jQuery has an exposed variable (that for some reason isn't listed anywhere in the jQuery docs) called $.timers, which holds the array of animations currently taking place.

function animationsTest (callback) {     // Test if ANY/ALL page animations are currently active      var testAnimationInterval = setInterval(function () {         if (! $.timers.length) { // any page animations finished             clearInterval(testAnimationInterval);             callback();         }     }, 25); }; 

Basic useage:

// run some function with animations etc     functionWithAnimations();  animationsTest(function () { // <-- this will run once all the above animations are finished      // your callback (things to do after all animations are done)     runNextAnimations();  }); 
like image 719
Mark Pieszak - Trilon.io Avatar asked Aug 24 '12 20:08

Mark Pieszak - Trilon.io


2 Answers

You can use jQuery's $.Deferred

var FunctionOne = function () {   // create a deferred object   var r = $.Deferred();    // do whatever you want (e.g. ajax/animations other asyc tasks)    setTimeout(function () {     // and call `resolve` on the deferred object, once you're done     r.resolve();   }, 2500);    // return the deferred object   return r; };  // define FunctionTwo as needed var FunctionTwo = function () {   console.log('FunctionTwo'); };  // call FunctionOne and use the `done` method // with `FunctionTwo` as it's parameter FunctionOne().done(FunctionTwo); 

you could also pack multiple deferreds together:

var FunctionOne = function () {   var     a = $.Deferred(),     b = $.Deferred();    // some fake asyc task   setTimeout(function () {     console.log('a done');     a.resolve();   }, Math.random() * 4000);    // some other fake asyc task   setTimeout(function () {     console.log('b done');     b.resolve();   }, Math.random() * 4000);    return $.Deferred(function (def) {     $.when(a, b).done(function () {       def.resolve();     });   }); }; 

http://jsfiddle.net/p22dK/

like image 179
Yoshi Avatar answered Oct 05 '22 02:10

Yoshi


add the following to the end of the first function

return $.Deferred().resolve(); 

call both functions like so

functionOne().done(functionTwo); 
like image 33
quemeful Avatar answered Oct 05 '22 01:10

quemeful