TheZ
TheZ

Reputation: 38

How to stop a Javascript function call within setTimeout after it has been fired?

I have a div that listens for a "mouseenter" event, and fires a libraryFunction (that I cannot edit) after 5 seconds (implemented with setTimeout).

However, if the user clicks the div within those 5 seconds, the setTimeout should be cancelled, and the function should not run (implemented with clearTimeout). The click will also remove an element that the libraryFunction relies on.

Currently I have the code below:

var timeoutVar;
$("#mydiv").on("mouseenter", function(event) {
    timeoutVar =  setTimeout(function() {
        runLibraryFunction(object);
    }, 5000);
});

$("#mydiv").on("click", function(event) {
    clearTimeout(timeoutVar);
    removeObject(object);
});

This works for the most part, however, there is an edge case when the div is clicked just after 5 seconds, and while runLibraryFunction() in executing. Because the "click" event removes the object that the runLibraryFunction needs, and this happens while runLibraryFunction is running, runLibraryFunction then throws an error.

Is there a way to stop the runLibraryFunction() call after it has been fired?

Upvotes: 2

Views: 1426

Answers (3)

Carsten Massmann
Carsten Massmann

Reputation: 28196

You could add a property to the object when starting the library function thereby protecting it from being removed like:

var timeoutVar;
$("#mydiv").on("mouseenter", function(event) {
    timeoutVar =  setTimeout(function() {
        object.keepmealive=1;
        runLibraryFunction(object);
        if (object) delete object.keepmealive;
    }, 5000);
});

$("#mydiv").on("click", function(event) {
    clearTimeout(timeoutVar);
    if (!object.keepmealive) removeObject(object);
});

This approach assumes that your library function will somehow take care of deleting or doing whatever needs to be done to object, so once it has started running there is no necessity for the delete function any more. It will stay in place and will be ready to act on another possible future event.

Upvotes: 1

pygeek
pygeek

Reputation: 7404

I would unbind the event during processing, and rebind it afterwards using s recursive function like so:

var timeoutVar;
var init = function(){
  $("#mydiv").on("mouseenter", function(event) {
    timeoutVar =  setTimeout(function() {
        $("#mydiv").off()
        runLibraryFunction(object, function(){
          init()
        });
    }, 5000);
  });
};

$("#mydiv").on("click", function(event) {
    clearTimeout(timeoutVar);
    removeObject(object);
});

init();

Upvotes: 0

void
void

Reputation: 36703

Tricky but will work

timeoutVar =  setTimeout(function() {
        setTimeout(function(){ 
            if(object)
            runLibraryFunction(object);
        },1000);
    }, 5000);

Keep rest same.

or use immediately invoked functions

timeoutVar =  setTimeout(function() {
                  (function(object){ 
                      runLibraryFunction(object);
                   })(object);
              }, 5000);

Now object will always be accessible

Upvotes: 2

Related Questions