fent
fent

Reputation: 18205

Best way to prevent a javascript function from executing while it already is or another one is?

I'm using jquery and what I'm doing is binding the toggle method to a number of buttons on a webpage. It looks something like this

$('.button').toggle(function(){
  // first function
}, function(){
  // second function
});

However, there are animation in both of those functions. So a user can click the button while the first or second function is executing. And this messes up the order of the HTML elements and may make them move to the end of the page. Because essentially what these functions do is move one element to the end on the first click, and on the other click move it back where it originally was.

Of course, it is difficult to click the button once it is moving around the page. But it's possible.

Upvotes: 2

Views: 1349

Answers (5)

austinfromboston
austinfromboston

Reputation: 3780

Seems like you'll be happier implementing your own toggle. Toggle really only works for cases with 0 additional logic.

$('.button').click( 
function () {
  if( $(self).is(":animated") {
    return false;
  }
  if($(self).is(".rolledup")) {
     self.apply(roll_window_down);    
  } else {
     self.apply(roll_window_up);    
  }
});



function roll_window_up() {
  $(self).addClass( 'rolledup' );

  // first function    
}

function roll_window_down() {
  $(self).removeClass( 'rolledup' );
  // first function    
}

Upvotes: 0

geocar
geocar

Reputation: 9305

You need a queue. You can build one with a semaphore variable, but jQuery already provides one, so maybe you want to use it:

$('.button').toggle(function() {
  $(document).queue("foo", function() {
    ...
  });
}, function() {
  $(document).queue("foo", function() {
    ...
  });
});

jQuery normally uses the "fx" queue to serialize animations, but you can use this "foo" queue for whatever you want.

The queue can be put on any object, so maybe you want to put it on the container that has all the .button objects in it. You cannot put it on the button (this) themselves, or you'll be back to where you're at now.

Once you've done that, all you really need to do is abort an animation. This can be done by expressly emptying the "fx" queue, or you can use $('.button').stop(); to stop all the old animations.

Upvotes: 0

AnthonyWJones
AnthonyWJones

Reputation: 189505

You need to place the two functions you pass to toggle in a context in which you can hold a flag to control function entrance:-

(function() {
  var toggling = false;
  $('.button').toggle(function(){
    if (!toggling) {
      toggling = true;           
      // first function
      toggling = false;
    } else {
      // whatever you want to happen if re-entrance attempted
    }
  }, function(){
    if (!toggling) {
      toggling = true;           
      // second function
      toggling = false;
    } else {
      // whatever you want to happen if re-entrance attempted
    }
  })
 )();

N.B. This serialises all toggles of elements that have the .button class. IOW there is only one toggling flag for all buttons. If you want each button to have its own toggling flag:-

$('.button').each(function() {
  var toggling = false;
  $(this).toggle(function(){
    if (!toggling) {
      toggling = true;           
      // first function
      toggling = false;
    } else {
      // whatever you want to happen if re-entrance attempted
    }
  }, function(){
    if (!toggling) {
      toggling = true;           
      // second function
      toggling = false;
    } else {
      // whatever you want to happen if re-entrance attempted
    }
  });
 );

Upvotes: 0

Sampson
Sampson

Reputation: 268424

You could use a flag. Set a flag 'isAnimating' to true when an animation begins, and false when it ends. Any subsequent animation can only proceed if this value is false.

You could also possibly check to see if the :animated selector applies to the owner of the event. And base your decisions off of that.

Upvotes: 5

cwap
cwap

Reputation: 11287

You could use a bool as a semiphore.. Obviously, this is in no way secure, but javascript doesn't really support locking, so you could easily have deadlocks and / or race conditions with this approach, but it will work 99,9% of the times :)

Upvotes: 3

Related Questions