Can I run setTimeout / setInterval inside $.submit()? - javascript

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.

Related

How to stop a function during its execution - JavaScript

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

javascript callback function after several jQuery calls

I got the following code:
$('#some_object_id').hide();
$('div#some_version_div').hide();
$('#some_another_object_id').show();
someFunction();
I want to issue my someFunction() only after the last of these 3 finishes its action. The problem is that from time to time they finish in different order (ie now the last may be the second, the other time the first one etc.) Now someFunction() fires without waiting for these 3 to finish. Any ideas how to fix it? Thank you.
jQuery's hide() and show() functions accept a function as their argument which is called when they finish. (aka, a callback).
$('selector').hide(function onFinish() {
console.log('done')
})
To combine three of them together, I'd convert them to a Promise, like so:
function promisify(func,selector){
return new Promise(function (resolve) {
$(selector)[func](resolve)
})
}
Promise.all([
promisify('hide', '#test'),
promisify('hide', '#test1'),
promisify('show', '#test2')
]).then(function onFinish() {
console.log('done!')
})
You can pass a callback function to hide, and show that gets executed when the animation is complete. So if you want them to execute in order just call each one in the callback of the previous one.
$('#some_object_id,div#some_version_div').hide(()=>{
$('#some_another_object_id').show(()=>{
someFunction();
});
});
And if you want to prevent a bunch of inner callbacks, and not require each animation run dependent of the others, you could use a flag. Increment the flag in each callback, check to see if its at a certain value, and then execute your function if it is.
var flag = 0;
function incrementFlag(){
flag++;
if(flag>=2){
flag=0;
someFunction();
}
}
$('#some_object_id,div#some_version_div').hide(incrementFlag);
$('#some_another_object_id').show(incrementFlag);
You could also modify the above to use a Promise, but will leave that for you to try.
You should use a variable that you initially set to 0 and increase on every complete call. As soon as the variable hit the value 3 and can call your function:
var completed = 0;
elem.hide(400, function(){
completed++;
if(completed > 2) someFunction();
});
//same for other elements...

give a Timeout function an Id, but then how do i trigger it?

If i give an ID to a JavaScript setTimeout function, how do I then execute or trigger it?
var timerId = setTimeout(function(){alert('doh')}, 1000);
//timerId; doesn't work,
//trigger it here
clearTimeout(timerId)
The action of calling the setTimeout() should execute it. I believe what you are trying to do is have this action repeat itself every second. For that you'll need to use setInterval() instead:
var timerId = setInterval(function(){alert('doh')}, 1000);
// you'll get an alert every second untill clearTimeout(timerId) is called.
As #j08691 says, you probably don't see the alert because you're calling clearTimeout() immediatly after you call setTimeout().
As a side note, you probably don't want to use the alert() function to debug this as alerts are a blocking action - no other JS will be executed while the alert is being displayed. You'll be much better off using console.log() to for this type of debugging. It's not blocking and will allow you very easily to inspect your variables.
The only use the return value of setTimeout has is to cancel the timer, which you are already doing with clearTimeout.
If you want to trigger it early, then you should clear it and then call the original function.
For example:
function doh(){
alert('doh')
}
var timerId = setTimeout(doh, 1000);
clearTimeout(timerId)
doh();

Want to set delay in javascript

I want to set delay in javascript code so that XML file generated before running of javascript . Here is my html code
<body onLoad="Func1Delay()">
<div id="map"></div>
</body>
In this Func1Delay() function i have written code to delay execution of javascript
function Func1Delay()
{
setTimeout("load()", 3000);
}
load() is javascript function ? how can i delay execution of javascript code so that xml file successfully generated before code execution??
Seems like your downloadUrl function provides a callback. The callback function fires automatically, after the XML is loaded. You do not need a 3 second delay, just move your logic inside the callback function. Something like this:
function Func1Delay() {
downloadUrl("location.xml", function (data) {
var xml = data.responseXML;
// do any thing with xml, it is loaded!
// alert(xml);
});
}
That's how you do it, except you don't want to use a string (although it works — provided you have a function called load defined at global scope). setTimeout schedules a function to be called a given number of milliseconds later.
It's better to give it an actual function reference:
function Func1Delay() {
setTimeout(load, 3000);
function load() {
// Stuff to do three seconds later
}
}
Note that the event you're using to trigger it, the onload of body, already happens really, really late in the page load cycle, and so whatever you're waiting for may already be done; conversely, if it might take more than three seconds, you might not be waiting long enough. So if there's something you can check to see whether it's done or not, you can poll, like this:
function Func1Delay() {
check();
function check() {
if (theWorkIsDone) {
// Do something with the work
}
else {
// Check back in 100ms (1/10th of a second)
setTimeout(check, 100);
}
}
}
You want the function to execute as soon as possible, but in every case after your xml has been successfully generated.
In this case you should prevent using a fixed amount of time (because you don't know the value exactly), but try the following:
function load(){
if (/*check here if the xml has *not yet* been generated*/){
setTimeout(load,50); // try again in 50 milliseconds
return;
}
// do your stuff here
}
This loops as long as your xml is not ready, and kicks in as soon as it's available.
General about setTimeout:
You can pass a string, but this is highly discouraged from for several reasons.
Instead pass a function reference or a function like this:
// function reference
setTimeout(load,3000) // no `()` !
// function
setTimeout( function(){load()},3000)
If you need paramters be passed to the function, you can't use the first option but need to use the second one, where you can easily pass them load(params).
If you pass a function like this: setTimeout(load(),3000) it executes the function load and passes its return value to the timeout. You however want the function invoked after 3 seconds and thus only pass the reference to the function.
Notice however, that you have a different scope if you execute the functions this way.

Is it OK to call clearInterval inside a setInterval handler?

I have a piece of Javascript that checks for a condition (via an AJAX call) every n seconds. If that condition is true, it stops checking. I have implemented it in the following way:
var stopTimer;
var timerId = setInterval(function() {
/* Make Ajax Calls and set stopTimer */
if (stopTimer) {
clearInterval(timerId);
}
}, 10000);
However, I find erratic behaviour: Works sometimes, but at other times, it keeps checking forever. I have checked that (as much as is possible) there is no error in any part of the code.
I am therefore suspecting that calling clearInterval inside a setInterval handler might be the culprit. Is that right? Is it OK to call clearInterval inside a setInterval handler?
Thank you for your attention
It's safe. The issue is probably to do with stopTimer not being set as you expect.
I don't think there will be any issue with your code unless the AJAX function is erroneous. You have to take care of the success and error callbacks of the AJAX function so that there won't be any issue with the loop not being stopped.
Also I think you are constantly polling the server for a response and then doing the appropriate action. You can use Reverse AJAX to do this kind of process.
Make sure you're not inadvertently re-using the same timer name elsewhere in your code which would result in you always stopping the second timer to be defined.
Either give the timer a unique name, or scope it to a function
var timerForAjax = setInterval(function() {
/* Make Ajax Calls and set stopTimer */
if (stopTimer)
{
clearInterval(timerForAjax);
}
}, 10000);
I was careless enough to call my timer interval and didn't realize I was creating two timers in the same scope both called interval. Blamed iOS8 for about an hour until I realized that that was nothing to do with it.

Categories