I am trying to use setTimeout for a performance test using console.time() and console.timeEnd(). However, setTimeout() isn't delaying the for() loop.
Here is the JS Fiddle:
// Start the timer.
console.time('testFor');
for ( i = 0; i < 5; i++ ) {
setTimeout( console.log('The number is ' + i), 2000 );
}
// End the timer, get the elapsed time.
console.timeEnd('testFor');
How can I make setTimeout() work in my script and why is it not working for me?
Others have already suggested excellent solutions to your problem - I'd like to offer a closer examination of what was happening with your code.
setTimeout doesn't delay the advancement of your code (like sleep does in other languages) but instead defers running another block of code. It's a weird concept that can be hard to understand; consider the following example:
console.time("Main Program");
console.time("Defered Code");
setTimeout(deferedCode, 1000);
console.timeEnd("Main Program");
function deferedCode() {
console.timeEnd("Defered Code");
}
If we look at the console after running this code, we'll see "Main Program" print out almost immediately, and "Defered Code" roughly a second later.
We've asked setTimeout to run the function deferedCode at a time 1000 ms in the future, and then let the rest of the code run.
Notice also that deferedCode is passed to setTimeout without (). We're passing the function itself and not the result of deferedCode to setTimeout so that setTimeout can choose when to run it.
You could do this without a loop, just using recursion:
var i = 0;
var logNumber = function(){
console.log('The number is ' + i);
i++;
if(i < 5){
setTimeout(logNumber, 2000);
}
}
logNumber();
setTimeout is asynchronous. If you want to call a certain piece of code at regular intervals, use the setInterval function.
I think this code is close to what you are trying to do:
// Start the timer.
console.time('testFor');
var i = 0;
var finish = 5;
var t = setInterval(function() {
if (i < finish) {
console.log('The number is ' + i);
i++;
} else {
clearInterval(t);
// End the timer, get the elapsed time.
console.timeEnd('testFor');
}
}, 2000);
Related
My setTimeout statements are making function calls instantly instead of waiting the time I specified and I'm not sure why. It should take 10 seconds for the for loop and then 110 seconds to change a boolean value from T to F.
for(var c = 0; c < 10; c++)
{
setTimeout(function()
{
gold = gold + clickerPower;
$("#totalGold").html("Gold: " + gold);
console.log("Clicked!");
}, 1000);
}
setTimeout(function(){frenzyActive = false;}, 110000);
Starting a timeout is an asynchronous operation. setTimeout accepts a function as it's first argument because it's registering that callback function to be invoked at a later time. Every iteration of the JavaScript event loop it checks to see if the appropriate time has passed and if so then it fires the registered callback. Meanwhile it's still moving on to run other code while it waits.
Your for loop is not waiting for anything. It iterates to 10 super fast and all you've done is register ten callbacks to fire all at the same time in exactly one second (the time is specified in milliseconds by the way, so 1000 = 1 second).
You need setInterval.
var count = 0;
var intervalId = setInterval(function () {
gold = gold + clickerPower;
$('#totalGold').html('Gold: ' + gold);
console.log('Clicked!');
count++;
if (count === 10) {
clearInterval(intervalId);
frenzyActive = false;
}
}, 1000);
That function will run once every second and increment a count variable each time. When it reaches 10 we call clearInterval and give it the intervalId returned from setInterval. This will stop the interval from continuing.
Take a gander at this post I wrote back when I too was confused about asynchronous callbacks :)
http://codetunnel.io/what-are-callbacks-and-promises/
I hope that helps :)
Good luck!
It will not take 10 seconds to execute the loop. Look will execute immediately and the anonymous function will be enqueued 10 times to be executed after 1 second.
The last call to setTimeout will cause the anonymous function to be executed after 110 seconds.
To ensure that the anonymous function within the loop is called sequentially, 10 times, after a gap of 1 second each, do the following:
var c = 0;
setTimeout(function() {
if(c < 10) {
gold = gold + clickPower;
console.log("Clicked");
c++;
setTimeout(arguments.callee, 1000);
//^^ Schedule yourself to be called after 1 second
}
}, 1000);
I did come across this challenge today, and the answer provided by #Guarav Vaish set me on a path to success. In my case, I am using ES6 syntax and its worth noting that the arguments.callee is deprecated. However, here is how I'd write the same solution as contributed by Vaish:
var c = 0;
setTimeout(function named() {
if(c < 10) {
gold = gold + clickPower;
console.log("Clicked");
c++;
setTimeout( ()=>{ named() }, 1000);
//^^ Schedule yourself to be called after 1 second
}
}, 1000);
Note: I am simply using a named function in place of the anonymous one in the original solution. Thank you. This was really helpful
Learning about callbacks and the solution to this problem eludes me.
It should print a number every second counting down until zero. Currently, it logs the numbers from 10 - 0 but all at once and continues in an infinite loop.
Please help me to gain a better understanding of this situation. I have read up on callbacks and have a conceptual understanding but execution is still a bit tricky.
var seconds = 0;
var countDown = function(){
for(var cnt = 10; cnt > 0; cnt--){
setTimeout(function(x){
return function(){
seconds++
console.log(x);
};
}(cnt), seconds * 1000);
}
}
countDown()
The way your code is working now, it executes a for loop with cnt going from 10 to 1. This works. On each iteration, it schedules a new function to be run in seconds * 1000 milliseconds, carefully and properly isolating the value of cnt in x each time. The problem is that seconds is 0, and it will only be changed once a callback executes; but by the time a callback executes, all of them will already have been scheduled for execution. If you need seconds * 1000 to vary while you’re still scheduling them all (while the for loop is still running), you need to change seconds in the loop, rather than inside one of the callbacks.
Read up on IIFEs to see how they work. In this situation, you're creating a closure of the value you want to print. You had the right idea, but your syntax was off.
var seconds = 0;
var countDown = function () {
var cnt = 10;
// simplify your loop
while (cnt--) {
// setTimeout expects a function
// use an IIFE to capture the current value to log
setTimeout((function (x) {
// return the function that setTimeout will execute
return function (){
console.log(x + 1);
};
}(cnt)), (++seconds) * 1000);
}
};
countDown();
This question already has answers here:
Sleep in JavaScript - delay between actions
(15 answers)
Closed 9 years ago.
I want to stop execution for 2 seconds.
<html>
<head>
<title> HW 10.12 </title>
<script type="text/javascript">
for (var i = 1; i <= 5; i++) {
document.write(i);
sleep(2); //for the first time loop is excute and sleep for 2 seconds
};
</script>
</head>
<body></body>
</html>
For the first time loop is excute and sleep for 2 seconds. I want to stop execution for two seconds?
Before using this code, please read all comments.
Javascript is single-threaded, so by nature there should not be a sleep function because sleeping will block the thread. setTimeout is a way to get around this by posting an event to the queue to be executed later without blocking the thread. But if you want a true sleep function, you can write something like this:
function sleep(miliseconds) {
var currentTime = new Date().getTime();
while (currentTime + miliseconds >= new Date().getTime()) {
}
}
Note: The above code is NOT recommended.
There's no (safe) way to pause execution. You can, however, do something like this using setTimeout:
function writeNext(i)
{
document.write(i);
if(i == 5)
return;
setTimeout(function()
{
writeNext(i + 1);
}, 2000);
}
writeNext(1);
You can use setTimeout to do this
function myFunction() {
// your code to run after the timeout
}
// stop for sometime if needed
setTimeout(myFunction, 2000);
This Link might be helpful for you.
Every time I've wanted a sleep in the middle of my function, I refactored to use a setTimeout().
There's no way to stop execution of your code as you would do with a procedural language.
You can instead make use of setTimeout and some trickery to get a parametrized timeout:
for (var i = 1; i <= 5; i++) {
var tick = function(i) {
return function() {
console.log(i);
}
};
setTimeout(tick(i), 500 * i);
}
Demo here: http://jsfiddle.net/hW7Ch/
function animateGraph() {
var graph;
for(i=0; i<10; i++)
{
var start = new Date();
while((new Date()) - start <= 500) {/*wait*/}
document.getElementById("timeMark").innerHTML = phoneX[i].epoch;
}
}
The loop works. The wait works. But the document.getElement is not showing up until the last item in the array...why?
Using setTimeout will allow the code to run and not lock up the page. This will allow it to run the code and will not effect other elements on the page.
var cnt = 0;
(function animateGraph() {
document.getElementById("timeMark").innerHTML = phoneX[cnt].epoch;
cnt++;
if (cnt<10){
window.setTimeout(animateGraph,500);
}
})();
The while loop, waiting for a datetime, is not a good way to wait - it just blocks execution. It keeps the browser (including UI, and its updating) frozen until the script finishes. After that, the window is repainted according to the DOM.
Use window.setTimeout() instead:
function animateGraph(phoneX) {
var el = document.getElementById("timeMark")
var i = 0;
(function nextStep() {
if (i < phoneX.length )
el.innerHTML = phoneX[i].epoch;
i++;
if (i < phoneX.length )
window.setTimeout(nextStep, 500);
})();
}
Please note that this runs asynchronous, i.e. the function animateGraph will return before all phoneXes are shown.
Use setTimeout instead of a while loop.
https://developer.mozilla.org/en/DOM/window.setTimeout
Also try something like this.
Javascript setTimeout function
The following snippet uses a helper function to create the timers. This helper function accepts a loop counter argument i and calls itself at the end of the timer handler for the next iteration.
function animateGraph() {
var graph;
setTimeMarkDelayed(0);
function setTimeMarkDelayed(i) {
setTimeout(function() {
document.getElementById("timeMark").innerHTML = phoneX[i].epoch;
if (i < 10) {
setTimeMarkDelayed(++i);
}
}, 3000);
}
}
You actually need some sort of helper function, otherwise you'll end up overwriting the value of i in your for loop in every iteration and by the time your timers run out, i will already be 9 and all handlers will act on the last element in phoneX. By passing i as an argument to the helper function, the value is stored in the local scope of that function and won't get overwritten.
Or you could use setInterval like Radu suggested, both approaches will work.
This question already has answers here:
What is the JavaScript version of sleep()?
(91 answers)
Closed 7 years ago.
All those setTimeout answers here don't work!
I just want to wait a few seconds between two functions, like this:
do_fn1();
wait(5000);
do_fn2();
From phpied.com:
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
I don't think you can. You'll probably have to
do_fn1();
window.setTimeout(do_fn2, 5000);
Two thoughts:
first of all why not wrap up all of the post delay statements into a wrapper function
var postDelayFunc = function(){
dosomething();
dosomethingelse();
onemorething();
}
then in your code pass this function as the parameter to setTimeout.
//your code
dofunc1();
setTimeout(postDelayFunc, 1000);
Alternatively take a look at jQuery deferred: http://msdn.microsoft.com/en-us/scriptjunkie/gg723713, although you will probably end up writing very similar code.
One thing struck me though about your responses to other answers and possibly where the confusion arises. I think you are looking at your function and seeing a single thread you just want to hold up for a while before carrying on.
You should not do this though in javascript as it ties up the entire browser and will annoy the hell out of users. Instead what you are in effect doing when you use setTimeout, is indicating that when the timeout expires another thread will pick up and execute the passed in function.
As soon as the timeout has been set, the executing thread will continue with the next line (which is why you think the timeout isn't working). What you probably need to do, is set the timeout, and put ALL the post-execution steps into the function handed off to the timer as indicated above.
Saying they all don't work without an example is big call because I'm sure they probably do.
How about this,
do_fn1();
setTimeout(do_fn2, 5000);
All those setTimeout answers here don't work!
Of course they do:
function a() {
alert("I'm pretty sure...");
}
function b() {
alert("...that they work just fine.");
}
a();
setTimeout(b, 5000);
Another hack I will probably use, however personally I would not recommend it.
Check out here http://jsfiddle.net/S6Ks8/1/
function parseSleeps(func){
var fdef = func.toString();
var fbody = fdef.match(/\{([\s\S]*)\}/)[1].split(/sleep\(.*?\)\;?/);
var sleeps = fdef.match(/sleep\((.*?)\)/g);
var fargs = fdef.match(/\(([\s\S]*?)\)/)[1];
var fbodyNew = [];
var times = [];
fbodyNew.push(fbody.shift(), '\n');
for(var i = 0; sleeps && i < sleeps.length; i++){
var sec = sleeps[i].match(/\d+/)[0];
times.push(sec);
fbodyNew.push('setTimeout(function(){\n');
fbodyNew.push(fbody.shift(), '\n');
}
while(times.length){
var sec = times.pop();
fbodyNew.push('}, ', sec, ');\n');
}
return new Function(fargs, fbodyNew.join(''));
}
// Your code from here
function a(str1, str2){
alert(str1);
sleep(3000);
alert(str2);
}
var func = parseSleeps(a);
func('here', 'there');
The smartest way would be to have something like
function a() {
// Do stuff
setTimeout(b, 42)
}
function b() {
// Do other stuff delayed
}
Never "block" any Threads in JS - if you think you have to do there is definately a "cleaner" way to do achieve your aim.