the .defer(5000) is causing a too much recursion error in JavaScript. How do I delay the execution by 5 seconds?
rotate: function () {
if (!paused) {
this.show(counter);
counter = counter + 1;
if (counter === Spire.Rotator.data.items.length) {
counter = 0;
}
Spire.Rotator.rotate().defer(5000);
//$.proxy(Spire.Rotator.rotate, Spire.Rotator).defer(delay);
}
}
This entire line:
Spire.Rotator.rotate().defer(5000);
is wrong. Because of the parentheses just after rotate, your function is immediately calling itself over and over again (infinite recursion). Removing the parentheses will fix that problem, but the code will probably not work. To fix the code, use the browser's window.setTimeout method, which accepts a function and a delay (in milliseconds) as two arguments:
setTimeout(function() {
Spire.Rotator.rotate();
}, 5000);
Why not just setTimeout(Spire.Rotator.rotate, 5000);? The reason is that this in that function would be window rather than Spire.Rotator. (There's plenty of information on the Internet about this.) Why not setTimeout("Spire.Rotator.rotate()", 5000);? That's a quite dated (deprecated) way to use the method that suffers from the same pitfalls of eval, a function that some JavaScript programmers including Douglas Crockford recommend not using.
Simply substitute this:
Spire.Rotator.rotate().defer(5000);
With this:
setTimeout(Spire.Rotator.rotate, 5000);
setTimeout() is javascript's native way of executing some Javascript code after a specified amount of time.
Actually, in your code, defer() never gets called. Assuming the rotate method you're defining is for the Spire.Rotator object what happens is:
rotate() calls rotate() calls rotate() calls rotate() .... [to infinity]
After infinity number of calls the return value of the infinitieth call will then call the defer method. But you have to wait for infinity calls to happen which takes eternity seconds to complete.
What you need is setTimeout().
Related
I am struggling to think of a use case in web-application development that needs to use setInterval.
The "danger" with setInterval being that it just queues up callbacks should one not complete within the allocated interval.
Furthermore, the behaviour of setInterval can be simulated with setTimeout or requestAnimationFrame without this "danger".
Given this, can someone provide me with a use-case where setInterval is the superior/more appropriate option?
Edit:
Thought I'd jot down my findings.
setInterval is an easy way to have something run at even-ish intervals. The intervals will mainly be quite accurate, but if the event loop is blocked, then they might be completely inaccurate.
var x = 0;
setInterval(function() {
waitBlocking(5000);
document.write(x++);
},100);
function waitBlocking(ms) {
var start = Date.now();
while((Date.now() - start) < ms) {}
}
As far as I can tell, setInterval is useful not if you want evenly spread interval callback invocations (see above), but if you want a convenient way of having a specific number of callback invocations in a period, spread across the timeframe as close as possible to when they should have run. Which seems like a rather narrow use case.
I'm sure I am missing something.
Edit 2:
This is basically the best approximation of a clock JS can achieve, so I guess setInterval is the "clock timer". Presumably this was useful in applications that needed simple clocks.
The use-case where setTnterval is appropriate is when you want to execute a function at an exact time. setInterval and setTimeout has subtitle differences. setInterval execute it function after delay starting from the time when the previose setInterval fired.
setInterval is also not reclusive so there is no fear of closures and memory leaks. More details can however be found here
Below is the code for a typical setInterval function
var intervalID = window.setInterval(myCallback, 500);
function myCallback() {
// Your code here
}
Where as to achieve the same function using setTimeout you will have to create a recursion which can create closures and then the problem of memory leaks comes in as demonstrated below.
function startTimer() {
var count = [1,2,3,4,5,6,7,8,9,0]
setTimeout(function() {
//do some stuff
count.push(100);//you have just create a closure
//and all the problems that is associated with it
startTimer();//this is where the recursion happens
}, 1000);
}
This question already has answers here:
Best way to iterate over an array without blocking the UI
(4 answers)
Closed 8 years ago.
I have some javascript on my page that takes a very long time to execute (between 10-30 seconds)
The code basically look like that :
//Iterate over all the elements in the array
for(int i=0; i<array.length; i++){
//Complex stuff for each element
}
The problem is that while this code is executing, the UI is not responsive.
Is there any way to solve this issue? I know javascript has some sort of asynchrony but I never really used it before...
Also, the order the elements are processed must always be the order that they appear in the array.
EDIT : I tried the solution below with setTimeout() and in the "duplicate", but it still doesn't fix my problem. I guess it's because the size of my array is not very big BUT the calculation for each element is pretty big.
Also the UI I want to be responsive is an animated loading gif. Since the calculation for each item is too big, the animation is sloppy.
Create a variable and set it to the starting value for your counter.
Create a function that:
Does whatever the body of the loop does
Increments the counter
Tests to see if the counter is still under the length and, if it is, calls the function again
At this point you will have functionality equivalent to what you have already.
To pause between each call of the function, and allow time for other functions to fire, replace the direct call to the function with a call to setTimeout and use the function as the first argument.
var counter = 0;
function iterator () {
//Complex stuff for each element
counter++;
if (counter < array.length) {
setTimeout(iterator, 5);
}
}
Javascript uses something called the "Event Loop". Basically, there is a single thread that executes the code for each event as it occurs.
There is a function called setTimeout that you can use to make your Javascript code run in a future iteration of the loop. One trick that some developers use to keep the UI responsive during a long-running Javascript task is to periodically invoke code to be run with a timeout of zero. This cause the code to execute almost immediately without locking the event loop.
For example, you could write
var i = 0;
setTimeout(myFunction, 0);
function myFunction() {
// complex stuff for each element.
i++;
if (i < array.length)
setTimeout(myFunction, 0);
}
Be aware that on modern browsers, as long as Javascript code is executing, the UI will be unresponsive. Some browsers will even pop up a message urging the user to kill the script; very bad!
Also, in modern browsers, there is a new feature called "Web Workers". Web Workers allow for Javascript code to be executed in a separate thread. You can create as many threads as you like, so consider using web workers as well if your task is easily parallelizable.
If you need the browser to update the page in the middle of your JS code, you need to yield to the browser, e.g. with a setTimeout, in a continuation passing style:
function doStuff(i) {
// do some stuff with index i
if (i < array.length) {
setTimeout(doStuff.bind(window, i + 1), 0);
}
}
doStuff(0);
I tend to do this kind of thing like so:
function doStuff(arr) {
if (arr.length === 0) {
// do whatever you need to do when you're done
return;
}
// Do body of computation here
// Or use setTimeout if your browser doesn't do setImmediate
setImmediate(function () { doStuff(arr.slice(1)); });
}
doStuff(actualArrayOfThings);
Basically, break your loop body up, and use recursion to run each part of the loop in order. It's pretty easy to break this out into a helper function, since the loop body itself is what varies. Something like:
function eachAsync(arr, body) {
if (arr.length === 0) {
// do whatever you need to do when you're done
return;
}
body(arr[0]);
setImmediate(function () { eachAsync(arr.slice(1), body); });
}
eachAsync(actualArrayOfThings, doStuff);
If your task is to process data without interfering with the user interface you can use WebWorkers
https://developer.mozilla.org/en/docs/Web/Guide/Performance/Using_web_workers
Note it's supported by modern browsers.
Use setTimeOut() if the for loop is doing some tidy work. It depends upon the complex stuff executing for each iteration.
Also, consider using JQuery/AJAX for executing it asynchronously.
EDIT: I would like to have one function being called and executed after one second of the last keyup event.
Here's my code: http://jsfiddle.net/gKkAQ/
JS:
function aFunction() {
setTimeout(function () {
console.log("1");
}, 1000);
}
$(document).ready(function () {
$("#Input").keyup(function () {
aFunction();
});
});
HTML:
<input type="text" id="Input"></input>
You can easily run the JSFiddle and see in your console that no matter how fast you type, the function will be executed regardless of its previous execution status (in this case, setTimeout is not done yet in 1 second, but if you keep typing, ALL function calls will be executed)
"you will see the function being executed every second. I would like it to be executed after one second of the last keyup action"
The setTimeout() function returns an id that you can pass to clearTimeout() to prevent the timeout from occurring - assuming of course that you call clearTimeout() before the time is up.
var timeoutId;
function aFunction() {
clearTimeout(timeoutId);
timeoutId = setTimeout(function () {
console.log("1");
}, 1000);
}
$(document).ready(function () {
$("#Input").keyup(function () {
aFunction();
});
});
There is no harm in calling clearTimeout() with the id of a timeout that did already happen, in that case it has no effect.
So the above code clears the previous timeout (if there is one) and then creates a new one, with the effect that the anonymous function with the console.log() will only be execute 1000ms after the user stops typing. If the user starts typing again after waiting more than 1000ms that will queue up another timeout.
NOTE: THIS ANSWER CORRESPONDS TO THE INITIAL, VERY GENERAL QUESTION, BEFORE IT WAS SUBJECT TO EXTENSIVE EDITING AND TRANSFORMED IN A VERY SPECIFIC ONE.
It depends on your exact execution environment. Theoretically, JavaScript is single-threaded. The situation you describe should never happen. In practice, however, it does happen (especially inside browsers), and there is no way to fully control it.
The closest alternative to "control" is to start by checking the value of a global "activation counter" variable. If it is 0, immediately increment it and proceed with execution. Decrement it when exiting.
Why this doesn't work? Because 2 activations can reach the test at the same time. As the variable is 0, both tests will succeed and both will procceed to increment the variable and execute. As with most syncronization/concurrency issues, problems will not occurr systematically, but randomly every now and then. This makes things difficult to detect, reproduce and correct.
You can try to ask two times for the variable, as in:
if( activationCounter <= 0 ) {
if( activationCounter <= 0 ) {
activationCounter++;
// Execution
activationCounter--;
}
}
In many circles this has been described as a solution to the problem, but it only reduces the probability of conflict (by quite a bit, but not to zero). It's just the result of a bad understanding of the "double-checked locking" pattern. Problems will still occur, but with much less frequency. I'm not sure if this is good or bad, as they will be even more difficult to detect, reproduce and correct.
So I know that there are differences between setTimeout and setInterval, but consider these two code examples:
function myFunction(){
setTimeout('myFunction();', 100);
doSomething();
}
setTimeout('myFunction();', 100);
and
function myFunction(){
doSomething();
}
setInterval('myFunction();', 100);
Note that in the first example I call setTimeout at the begining of the function and then I doSomething. Therefore there is no extra delay from doSomething(). Does that mean that those two examples do exactly the same? Or is there even more subtle difference?
They're functionally about the same, but there are differences. One difference is in how browsers handle it if doSomething takes longer than the interval. With setInterval, at least some browsers will just skip the next interval if doSomething is still running. So if you use 100ms as you have, and doSomething takes 110 ms to run, the next run won't happen until 90ms later (of course, all of these times are approximate).
Another difference is that with the setTimeout, you'll get a new handle every time, whereas with setInterval you get one handle.
Another difference with your examples as given is that in the setTimeout example, you're firing up a JavaScript parser/compiler every time, whereas with setInterval you're only firing up the parser/compiler once. But this difference shouldn't matter, because you shouldn't be doing that at all — see below.
But subtleties aside, what you have there is functionally the same.
Side note: It's not best practice to pass strings into either setTimeout or setInterval. Instead, pass in a function reference:
// setTimeout
function myFunction(){
setTimeout(myFunction, 100);
doSomething();
}
setTimeout(myFunction, 100);
// setInterval
function myFunction(){
doSomething();
}
setInterval(myFunction, 100);
Passing in a string fires up a JavaScript parser and does the same thing as eval. It should be avoided whenever possible (and it's almost always possible).
T.J. Crowder explained the main differences, one other more subtle could appear (I change the time scale as it's easier to explain) :
Lets plot the difference with a very big timeout time : 1 Day. You call both methods at 00:00 on Day 1 and let it run for 1 year...
1 Year latter your method called by setInterval will execute at 00:00 + some milliseconds (because you may not be the only one asking for the processors to do things at this exact moment and the OS timers have granularity anyway).
But your setTimeout method will occur latter, maybe around 00:01 because each day it would have been called a little after the requested time and requested to be called the next day at the same time...
PS: It could also be called before the requested time in some cases but more often than not it run after :-D
I thought I would try and be clever and create a Wait function of my own (I realise there are other ways to do this). So I wrote:
var interval_id;
var countdowntimer = 0;
function Wait(wait_interval) {
countdowntimer = wait_interval;
interval_id = setInterval(function() {
--countdowntimer <=0 ? clearInterval(interval_id) : null;
}, 1000);
do {} while (countdowntimer >= 0);
}
// Wait a bit: 5 secs
Wait(5);
This all works, except for the infinite looping. Upon inspection, if I take the While loop out, the anonymous function is entered 5 times, as expected. So clearly the global variable countdowntimer is decremented.
However, if I check the value of countdowntimer, in the While loop, it never goes down. This is despite the fact that the anonymous function is being called whilst in the While loop!
Clearly, somehow, there are two values of countdowntimer floating around, but why?
EDIT
Ok, so I understand (now) that Javascript is single threaded. And that - sort of - answers my question. But, at which point in the processing of this single thread, does the so called asynchronous call using setInterval actually happen? Is it just between function calls? Surely not, what about functions that take a long time to execute?
There aren't two copies of the variable lying around. Javascript in web browsers is single threaded (unless you use the new web workers stuff). So the anonymous function never has the chance to run, because Wait is tying up the interpreter.
You can't use a busy-wait functions in browser-based Javascript; nothing else will ever happen (and they're a bad idea in most other environments, even where they're possible). You have to use callbacks instead. Here's a minimalist reworking of that:
var interval_id;
var countdowntimer = 0;
function Wait(wait_interval, callback) {
countdowntimer = wait_interval;
interval_id = setInterval(function() {
if (--countdowntimer <=0) {
clearInterval(interval_id);
interval_id = 0;
callback();
}
}, 1000);
}
// Wait a bit: 5 secs
Wait(5, function() {
alert("Done waiting");
});
// Any code here happens immediately, it doesn't wait for the callback
Edit Answering your follow-up:
But, at which point in the processing of this single thread, does the so called asynchronous call using setInterval actually happen? Is it just between function calls? Surely not, what about functions that take a long time to execute?
Pretty much, yeah — and so it's important that functions not be long-running. (Technically it's not even between function calls, in that if you have a function that calls three other functions, the interpreter can't do anything else while that (outer) function is running.) The interpreter essentially maintains a queue of functions it needs to execute. It starts starts by executing any global code (rather like a big function call). Then, when things happen (user input events, the time to call a callback scheduled via setTimeout is reached, etc.), the interpreter pushes the calls it needs to make onto the queue. It always processes the call at the front of the queue, and so things can stack up (like your setInterval calls, although setInterval is a bit special — it won't queue a subsequent callback if a previous one is still sitting in the queue waiting to be processed). So think in terms of when your code gets control and when it releases control (e.g., by returning). The interpreter can only do other things after you release control and before it gives it back to you again. And again, on some browsers (IE, for instance), that same thread is also used for painting the UI and such, so DOM insertions (for instance) won't show up until you release control back to the browser so it can get on with doing its painting.
When Javascript in web browsers, you really need to take an event-driven approach to designing and coding your solutions. The classic example is prompting the user for information. In a non-event-driven world, you could do this:
// Non-functional non-event-driven pseudo-example
askTheQuestion();
answer = readTheAnswer(); // Script pauses here
doSomethingWithAnswer(answer); // This doesn't happen until we have an answer
doSomethingElse();
That doesn't work in an event-driven world. Instead, you do this:
askTheQuestion();
setCallbackForQuestionAnsweredEvent(doSomethingWithAnswer);
// If we had code here, it would happen *immediately*,
// it wouldn't wait for the answer
So for instance, askTheQuestion might overlay a div on the page with fields prompting the user for various pieces of information with an "OK" button for them to click when they're done. setCallbackForQuestionAnswered would really be hooking the click event on the "OK" button. doSomethingWithAnswer would collect the information from the fields, remove or hide the div, and do something with the info.
Most Javascript implementation are single threaded, so when it is executing the while loop, it doesn't let anything else execute, so the interval never runs while the while is running, thus making an infinite loop.
There are many similar attempts to create a sleep/wait/pause function in javascript, but since most implementations are single threaded, it simply doesn't let you do anything else while sleeping(!).
The alternative way to make a delay is to write timeouts. They can postpone an execution of a chunk of code, but you have to break it in many functions. You can always inline functions so it makes it easier to follow (and to share variables within the same execution context).
There are also some libraries that adds some syntatic suggar to javascript making this more readable.
EDIT:
There's an excelent blog post by John Resig himself about How javascript timers work. He pretty much explains it in details. Hope it helps.
Actually, its pretty much guaranteed that the interval function will never run while the loop does as javascript is single-threaded.
There is a reason why no-one has made Wait before (and so many have tried); it simply cannot be done.
You will have to resort to braking up your function into bits and schedule these using setTimeout or setInterval.
//first part
...
setTimeout(function(){
//next part
}, 5000/*ms*/);
Depending on your needs this could (should) be implemented as a state machine.
Instead of using a global countdowntimer variable, why not just change the millisecond attribute on setInterval instead? Something like:
var waitId;
function Wait(waitSeconds)
{
waitId= setInterval(function(){clearInterval(waitId);}, waitSeconds * 1000);
}