views:

119

answers:

4

I have a javascript function that is being built to animate the collapse of a div, and then proceed with other jobs. The code is as follows:

function newsFeed() {

    var self = this;

    this.collapse = function(listingID,orig_height,curr_height,opacity) {

     var listing = document.getElementById(listingID);
     var reduceBy = 5;
     if(curr_height > reduceBy) {
      curr_height = curr_height-reduceBy;
      listing.style.overflow = "hidden";
      listing.style.height = (curr_height-40) + "px";

      if(opacity > 0) {
       opacity = opacity - 10;
       var opaque = (opacity / 100);

       listing.style.opacity=opaque;                      
       listing.style.MozOpacity=opaque;                   
       listing.style.filter='alpha(opacity='+opacity+')';
      }

      setTimeout(function() { self.collapse(listingID,orig_height,curr_height,opacity); },1);

     }else{

         return true;

     }
    }

    this.remove = function(listingID) {

     var listing = document.getElementById(listingID);
     var currHeight = listing.offsetHeight;

     if (this.collapse(listingID,currHeight,currHeight,100)) {

                // DO SOME OTHER STUFF

     }

    }

}

var newsFeed = new newsFeed();
newsFeed.remove('closeMe');

I cannot get the this.remove function to wait while this.collapse finishes and returns true. Is this impossible? What is the best way to go on?

Important: I would like to be able to use this.collapse with other functions yet to be built in the same fashion as I do here.

+2  A: 

There is no way you can pause the execution in Javascript till something else happens. All you can do is attach a callback function to collapse to call after it is done executing the final step.

As a sidenote, jQuery provides functions like fade(), animate() etc and supports queuing. If you don't want to use jQuery, you can still look at the code to see how it's implemented.

See the examples in this page.

Chetan Sastry
+3  A: 

I cannot get the this.remove function to wait while this.collapse finishes

That is correct, it is impossible to do so. In JavaScript there is a single flow of execution. When the browser calls your code you can do some processing, but for anything further to occur (timeouts or event calls) you must return control to the browser.

‘Asynchronous’ processes like collapse() are done by setting timeouts, so control must be returned to the browser many times; when remove() calls collapse() the first time it returns immediately after the first timeout is set; that timeout cannot be fired until remove() itself returns, so your 'if' code will only ever execute if the very first call to collapse() was the last frame of animation (ie. the element was 5px or smaller already). Otherwise collapse()'s ‘return true’ will just be returning true to the browser's timeout-caller, which doesn't care at all what value you return to it.

Some languages give you tools such as threads or coroutines that can allow an asynchronous routine to be run from a synchronous routine; JavaScript does not. Instead, remove() must supply collapse() with a callback function it can call itself on the last frame.

bobince
A: 

setTimeout is not a "sleep". The function will end right there and return "undefined".

To manage that, I think you should do something like:


var newsFeed = new newsFeed();
newsFeed.onaftercollapse = function () {
    newsFeed.remove('closeMe'); // "newsFeed" or "self"? must test
};

And then instead of return true;, the collapse() will end with:


if (self.onaftercollapse) self.onaftercollapse();
Havenard
A: 

This example demonstrates how to check if a function is complete.

function foo() {
  foo.complete = false;
  // your code here
  foo.complete = true;
}
foo.complete = false;

if (foo.complete) { // foo execution complete
  // your code here
}

This code demonstrates how to check if a function has been run once.

function foo() {
  // your code here
  foo.ranOnce || (foo.ranOnce = true);
}
foo.ranOnce = false;

if (foo.ranOnce) { // foo execution complete at least once
  // your code here
}
Eli Grey