How can I stop/terminate a function which is already executed and still running? For example, I have this function:
function foo() {
setInterval(function() {
console.log("Foo Executed !");
}, 3000);
}
foo();
Now, this foo() function will run for unlimited time, when a specific event occurs, let's say a stop button has been clicked, then I want to stop this function.
In my case the function doesn't have setInterval() function. And what if the foo() function don't have the setInterval() method, but just many lines of code that get executed and I want to stop it from executing after a specific event.
Stopping a running function is a bit different than what you are actually showing for code, which is an asynchronous operation happening outside of the function that initiated it.
Running functions can only be terminated from within the function and that is done with either a return statement or by throwing an exception.
return can be called conditionally so that the function doesn't always exit at the same point. This is often the case with form validation functions - - if something is determined to be invalid, a return is encountered so that the form is not submitted. If everything is valid, the return is skipped and the form is submitted.
Here's a simple example with return:
function foo1(){
console.log("Foo started...");
if(prompt("Type 1 to terminate right now or anything else to continue...") == "1"){
return; // Function will terminate here if this is encountered
}
console.log("Foo ending..."); // This will only be run if something other than 1 was entered
}
foo1();
And, here's an example with throwing an error (not something that is usually done):
function foo(){
console.log("foo started...");
for(var i = 0; i < 5; i++){
if(i === 3) { throw "I HATE 3!"; }
console.log(i);
}
console.log("foo ended...");
}
foo();
But, with Timers and Intervals, you'll need to call clearInterval() and/or clearTimeout() to stop them. These are different because, while some function may initiate the timer or interval, the timer runs outside of the JavaScript runtime environment as a WebAPI. For these, we have to send a message to the WebAPI that we want the timer to stop counting.
You say:
Now, this foo() function will run for unlimited time, when a specific
event occurs, let's say a stop button has been clicked, then I want to
stop this function.
But foo isn't running for an unlimited time. It's run once and then terminates. Then approximately 3 seconds later, the timer calls for the anonymous function you passed to it to be run and then that function terminates and approximately 3 seconds later the anonymous function runs again and then it again terminates and so on. The function isn't running consistently, the interval timer (the WebAPI that calls for the function to be invoked) is.
And what if the foo() function don't have the setInterval() method,
but just many lines of code that get executed and I want to stop it
from executing after a specific event.
Your question seems to imply that you want to stop a function that is currently executing when another event takes place. This can't really happen in JavaScript since JavaScript is a single-threaded environment. Any event can only be raised and handled after all other code is done processing. So, there really can't ever be a scenario like the one you mention, unless we are talking about asynchronous code. Asynchronous code is code that runs outside of the JavaScript runtime. With that kind of code, you can send a message to the WebAPI that is processing that external code that you would like to cancel/abort that processing and that is what we're doing when we call clearInterval().
See below:
document.getElementById("start").addEventListener("click", startInterval);
document.getElementById("stop").addEventListener("click", stopInterval);
// You'll need a variable to store a reference to the timer
var timer = null;
function startInterval() {
// Then you initilize the variable
timer = setInterval(function() {
console.log("Foo Executed!");
}, 1500);
}
function stopInterval() {
// To cancel an interval, pass the timer to clearInterval()
clearInterval(timer);
}
<button type="button" id="start">Start</button>
<button type="button" id="stop">Stop</button>
For that use return; in the place you want to kill the process
Related
Since setTimeout crashes in while loops.
I don't know if there is a way to do it but I am trying to make one.
This is how it looks so far.
<script>
var send = true;
function sendit()
{
alert("test");
return true;
}
while(true)
{
if(send == true)
{
send = false;
setTimeout(function(){
if(sendit() == true) {
send = true;
}
}, 5000);
}
}
</script>
Is it possible this way?
You haven't explained what you want your code to do. If you want it to alert "test" every 5 seconds then you need this:
<script>
function sendit()
{
alert("test");
// Call sendit() the next time, repeating
setTimeout(sendit, 5000);
}
// Call sendit() the first time
setTimeout(sendit, 5000);
</script>
No need for a loop, just get the function to schedule itself again.
My understanding is that what you're trying to do is the equivalent of Thread.sleep(5000) in a language like Java or C#. That functionality does not exist in JavaScript. If you want to do something some amount of time after your function's execution, put it in a timeout, but one way or another, that first function will still complete in the same frame unless you're performing an enormous amount of work.
Currently, your code is setting a timeout on sendit() a practically-infinite number of times before it returns. Since JavaScript is single threaded, even if 20 seconds passed, it still wouldn't have finished your function and couldn't start looking up timeouts it needs to process. What you should be doing is something like having the inside of the timeout set another timeout, and remove the enclosing while(true). That could allow for infinite, periodic behavior as I think you're looking for.
sample code:
var isExecutionOver = false,
myFunction = function() {
// does some asynchronous stuff and sets isExecutionOver to true
// when the asynchronous job is over.
};
myFunction();
// Kill myFunction if it takes more than 3 seconds
setTimeout(function() {
if(!isExecutionOver) {
// How do I kill myFunction?
}
}, 3*1000);
In the above snippet I am trying to kill (or in other words, stop execution of) myFunction if it is not able to do its job in given time (3 seconds in this case).
PS: Kindly assume that I do not have control over myFunction definition. The only place where I can work is inside setTimeout.
You have a very complicated question:
You can't actually kill a running function. You can sometimes set a flag that it can notice when it decides to check. It could stop doing what it is doing and return.
But remember that JavaScript is a single-threaded language. When the code in this function is running, there are few ways for any other code to set that flag.
Example 1: It seems like I remember something about how some browsers, for example, will let certain events be run from the event queue when an alert box pops up. Those events could set the flag.
Example 2: Another possibility is that the code in the function is not technically in the function but the function starts an interval timer that does the work. Any other code could set the flag and the code run at intervals could check the flag and stop repeating.
var abortWork = false;
function a() {
while (notDone) {
.. do some work ...
if (abortWork) {
return;
}
}
}
... whatever ...
abortWork = true;
You can stop a setTimeout() event that is waiting for the time to be over. (There is a similar way to stop a setInterval() repeated event.
var t = setTimeout(function() {
... code goes here ...
}, 20000);
... whatever ...
clearTimeout(t); // stop the timeout if it hasn't started running the function
You can stop an ajax request that is waiting for the response. (Note: An XHR object is also returned from pure javascript ajax call.) Note that the request has already gone to the server and this just tells it to ignore any future response to the request.
var xhr = $.ajax({ type: "POST", ... });
... whatever ...
xhr.abort(); //kill the request
I always run into this problem and seem to implement a nasty looking solution.
It seems like a common design pattern to fire an action immediately, but not let that action queue up if clicked rapidly / delay firing if previously called within a timeframe. In my real world example, I have an AJAX call being made, so if I don't prevent repetitive actions the browser queues requests.
How would you implement this differently? What other options are there?
function myFunction() {
console.log("fired");
}
var timeout = null;
$("#foo").click(function() {
// if not previously clicked within 1 second, fire immediately
if (!timeout) {
myFunction();
timeout = setTimeout(function() {
timeout = null;
}, 1000);
} else {
// clicked again within 1s
clearTimeout(timeout); // clear it - we can't have multiple timeouts
timeout = setTimeout(function() {
myFunction();
timeout = null;
}, 1000);
};
});
With your current code, if you repeatedly click "#foo" at an interval slightly less than one second, say every 800ms, on first click it will fire the function immediately (obviously), but then it will fire the function exactly once more one second after the last click. That is, if you click ten times at 800ms intervals the function will fire once immediately and a second time approximately 8 seconds (800ms * 9 + 1000ms) after the first click.
I think you're better off removing the else case altogether, so that on click it will fire the function if it has not been called within the last second, otherwise it will do nothing with no attempt to queue another call up for later. Not only does that seem to me like a more logical way to operate, it halves the size of your function...
On the other hand, since you mentioned Ajax, rather than disabling the function based on a timer you may like to disable the function until the last Ajax request returns, i.e., use a flag similar to your timerid and reset it within an Ajax complete callback (noting that Ajax complete callbacks get called after success or failure of the request).
In the case of an auto-complete or auto-search function, where you want to send an Ajax request as the user types, you might want to remove the if case from your existing code and keep the else case, because for auto-complete you likely want to wait until after the user stops typing before sending the request - for that purpose I'd probably go with a shorter delay though, say 400 or 500ms.
Regarding general structure of the code, if I wanted a function to be fired a maximum of once per second I'd likely put that control into the function itself rather than in a click handler:
var myFunction = function() {
var timerid = null;
return function() {
if (timerid) return;
timerid = setTimeout(function(){ timerid=null; }, 1000);
// actual work of the function to be done here
console.log("myFunction fired");
};
}();
$("#foo").click(function() {
myFunction();
});
The immediately invoked anonymous function that I've added makes it uglier, but it keeps the timerid variable out of the global scope. If you don't like that obviously you could simply declare timerid in the same scope as myFunction() as you currently do.
This answer is getting kind of long, but if you have a lot of different functions that all need some kind of repeat control in them you could implement a single function to handle that part of it:
function limitRepeats(fn, delay) {
var timerid = null;
return function() {
if (timerid) return;
timerid = setTimeout(function(){ timerid = null; }, delay);
fn();
};
}
// myFunction1 can only be called once every 1000ms
var myFunction1 = limitRepeats(function() {
console.log("fired myFunction1()");
}, 1000);
// myFunction2 can only be called once every 3000ms
var myFunction2 = limitRepeats(function() {
console.log("fired myFunction2()");
}, 3000);
$("#foo").click(function() {
myFunction1();
myFunction2();
});
Am I doing this right?
var jForm= $("form:first");
jForm.submit(function( objEvent ) { setTimeout(somefunction(),500) });
The form is used to upload a file using an invisible iFrame. The above attempt has led me to an infinite loop for some reason...
I will really wish to know if I am able to call a function with setTimeout while manipulating submit with jQuery.
Note: I have previously raised this question, but I suppose I have included way too much information for my question.
Unless you prevent the default submit action of your form, it will be submitted by that default action before the function in setTimeout has time to run.
$('form:first').submit( function(e){
e.preventDefault();
setTimeout( someFunction, 500 ); // NOT setTimeout(somefunction(),500)
});
Also, don't call the function in setTimeout(). Pass a reference to the function (as above).
Bad:
setTimeout( 'myfunc()', 500 ); // bad, uses eval, runs in global scope
setTimeout( myfunc(), 500 ); // bad, runs function immediately, then passes
// returned value into setTimeout -- unless you
// are returning a function from myFunc
Good:
setTimeout( myfunc, 500 ); // function runs after 500 msec delay
setTimeout( function(){ // anonymous function, works fine
do_this();
do_that();
}, 500 );
setTimeout( function myfunc(){ // or name the function, easier for debugging
do_this();
do_that();
}, 500 );
jForm.submit(function( objEvent ) { setTimeout("somefunction()",500) });
otherwise you will immediately call somefunction and execute the result in 500 milisecs
You probably want to return false at the end of the function to prevent the form submission, otherwise you're stuck with a race condition.
When the form is submitted, the page will start navigating somewhere else (the form's action). Unless you stop the form from submitting, somefunction() may not execute, or may not finish executing.
var jForm= $("form:first");
jForm.submit(function(objEvent) {
setTimeout(somefunction, 500);
return false; // Prevent form submission. Alternatively, you could call objEvent.preventDefault();
});
You seem to be mixing up setTimeout and setInterval. setInterval creates a loop, so if you pass setInterval a funcion that itself calls setInterval, you're asking for trouble.
I want to make sure I understand callbacks properly, and javascript timing etc. in general.
Say my code looks like this, is it guaranteed to execute in order?
SetList(); // initializes the var _list
Some.Code(_list, function(data) {
// update list
});
DoSomething(_list); // operates on _list
Update
What I am seeing is SetList calls, then DoSomething, then Some.Code.
Some.Code calls another function. so:
Some.Code(_list, function() {
//load _list from ajax request
Other.Code.WithCallback(_list, function(){....});
});
I guess to fix this, I have to add DoSomething to the inner function as another callback?
SetList(), Some.Code() and DoSomething() will execute in that order, one after the other. The anonymous function passed as the second argument to Some.Code() could be called during the execution of Some.Code() (before the function returns and DoSomething() is called) or it could be called at a later time by another function, and event handler or timer, it all depends on when you specified it to be called.
Since you're using ajax, the request to the remote server is made on a separate thread, so the executing javascript thread continues to run and call other functions until a response (or, more specifically, for the onreadystatechange event to fire). When the ready state of the ajax request changes, its readystatechange event handler is queued to be called -- meaning it will execute as soon as all currently executing scripts finish.
If you want DoSomething() to execute after the response is received via ajax, you should run it to the end of your callback function instead.
That code would execute in order:
SetList(), then Some.Code(), then function(data), then DoSomething().
JavaScript is single-threaded, and executes in order. The only way that things would happen out of sync is if you set an interval/timer within Some.Code() or function(data) that called another function.
If you had:
var i=0;
functionCall() //some long process that sets i=1;
if (i==1) { alert("In Order!"); } else { alert("Out of Order!"); }
That would alert "In Order," But if you had:
var i=0;
setTimeout(functionCall, 1000) //some long process that sets i=1;
if (i==1) { alert("In Order!"); } else { alert("Out of Order!"); }
That would execute "Out of Order," because the third line would execute before functionCall() is called.
Updated Answer
Because you are using Ajax, I'm guessing you are making an asynchronous call, which is the reason for the delay. You have a callback function, but it's still waiting to be called back, so Javascript moves on to execute the next line while it waits.
To execute in the order you want, you'll need to do this:
SetList(); // initilizes the var _list
Some.Code(_list, function(data) {
// update list
DoSomething(_list); // operates on _list
});
This way, you can ensure that DoSomething() is called when your callback method is called, and not before.