Looping setTimeout - javascript

I'm currently trying to wrap my head around some JavaScript.
What I want is a text to be printed on the screen followed by a count to a given number, like so:
"Test"
[1 sec. pause]
"1"
[1 sec. pause]
"2"
[1 sec. pause]
"3"
This is my JS:
$(document).ready(function() {
var initMessage = "Test";
var numberCount = 4;
function count(){
writeNumber = $("#target");
setTimeout(function(){
writeNumber.html(initMessage);
},1000);
for (var i=1; i < numberCount; i++) {
setTimeout(function(){
writeNumber.html(i.toString());
},1000+1000*i)};
};
count();
});
This is my markup:
<span id="target"></span>
When I render the page, all I get is "Test" followed by "4".
I'm no JavaScript genius, so the solution could be fairly easy. Any hints on what is wrong is highly appreciated.
You can play around with my example here: http://jsfiddle.net/JSe3H/1/

You have a variable scope problem. The counter (i) inside the loop is only scoped to the count function. By the time the loop has finished executing, is value is 4. This affects every setTimeout function, which is why you only ever see "4".
I would rewrite it like this:
function createTimer(number, writeNumber) {
setTimeout(function() {
writeNumber.html(number.toString());
}, 1000 + 1000 * number)
}
function count(initMessage, numberCount) {
var writeNumber = $("#target");
setTimeout(function() {
writeNumber.html(initMessage);
}, 1000);
for (var i = 1; i < numberCount; i++) {
createTimer(i, writeNumber);
}
}
$(document).ready(function() {
var initMessage = "Test";
var numberCount = 4;
count(initMessage, numberCount);
});
The createTimer function ensures that the variable inside the loop is "captured" with the new scope that createTimer provides.
Updated Example: http://jsfiddle.net/3wZEG/
Also check out these related questions:
What's going on under the hood here? Javascript timer within a loop
JavaScript closure inside loops – simple practical example

In your example, you're saying "2, 3, 4 and 5 seconds from now, respectively, write the value of i". Your for-loop will have passed all iterations, and set the value of i to 4, long before the first two seconds have passed.
You need to create a closure in which the value of what you're trying to write is preserved. Something like this:
for(var i = 1; i < numberCount; i++) {
setTimeout((function(x) {
return function() {
writeNumber.html(x.toString());
}
})(i),1000+1000*i)};
}
Another method entirely would be something like this:
var i = 0;
var numberCount = 4;
// repeat this every 1000 ms
var counter = window.setInterval(function() {
writeNumber.html( (++i).toString() );
// when i = 4, stop repeating
if(i == numberCount)
window.clearInterval(counter);
}, 1000);

Hope this helps:
var c=0;
var t;
var timer_is_on=0;
function timedCount()
{
document.getElementById('target').value=c;
c=c+1;
t=setTimeout("timedCount()",1000);
}
function doTimer()
{
if (!timer_is_on)
{
timer_is_on=1;
timedCount();
}
}

Related

setTimeout in javascript does not show updated value

why am I getting the outpupt 10 instead of 20. Why the setTimeout is not taking the latest value?
var a=10;
function foo(myvar){
console.log(myvar);
}
setTimeout(foo,1000,a);
a=20;
if I put setTimeout in a loop then it consoles the latest value
for (var i = 0; i < 3; i++) {
setTimeout(function log() {
console.log(i);
}, 1000);
}
3 3 3
This is because your setTimeout thread was initialized when the value for variable a is 10. There after you updated the value of variable a. But the value of parameter is still the old value 10.
var a = 10;
function foo(myvar) {
console.log('Value for param ', myvar);
console.log('Value for a ', a );
console.log('Thread Executed');
}
console.log('Thread Started');
setTimeout(foo, 1000, a);
a = 20;
console.log('Variable Updated');
What is happening in the other case was you are logging the value of the index i which is in the for loop. At the time of execution of console, the value of i will be the last value, which is 3
One issue is - you're not comparing like for like code
var a=10;
function foo(myvar){
console.log(myvar);
}
setTimeout(foo,10,a);
a=20;
is comparable to
var i;
function log(myvar) {
console.log(myvar);
}
for (i = 0; i < 3; i++) {
setTimeout(log, 10, i);
}
Whereas
for (var i = 0; i < 3; i++) {
setTimeout(function log() {
console.log(i);
}, 10);
}
Is exactly equivalent to
var i;
function log() {
console.log(i);
}
for (i = 0; i < 3; i++) {
setTimeout(log, 10);
}
and comparable to
var a=10;
function foo(){
console.log(a);
}
setTimeout(foo,10);
a=20;
You are passing a by value in the call to setTimeout(). Therefore no matter how many times you change the value of a after calling setTimeout() you'd not get any of the new values.
The following snippet would work:
var a=10;
function foo(){
console.log(a);
}
setTimeout(foo,1000);
a=20;
Because a is captured as part of the closure(foo())'s calling context. Notice that a is not passed to setTimeout() explicitly.
The second example you gave appears to work to you but it is actually exactly the same as the original sample it's just that you pass three different values - 1, 2, and 3 - to three consecutive calls to setTimeout(). If you added an if-statement inside the loop to ensure that you only call setTimeout() when i == 1 you'd see exactly the same behavior as in your first snippet.

How do I delay this code running in JavaScript?

I have written this code to change an image:
change = function(){
for (r=0; r<6; r++){
for (i = 0; i < 6 ; i++) {
setInterval(imgfile(number=i+1), 5000);
}
}
}
imgfile= function(number){
a = 'document.getElementById("imgdiv").src = "images/'+number+'.svg"';
eval(a);
}
The function change() is called when a button is clicked.
When I press the button the image changes straight to 6.svg, when I want it to go through the images 1, 2, 3, 4, 5, 6 and to repeat it 6 times. When I change setInterval to change.setInterval or imgfile.setInterval it doesn't work at all. How do I fix this?
change = function(i=0){
imgfile(i%6+1);//change image
if(i<36) setTimeout(change,5000,i+1);//next image in 5 seconds
}
imgfile= function(number){
document.getElementById("imgdiv").src = "images/"+number+".svg";//no need to use ev(i||a)l
}
Instead of loop/interval mess you can simply start a timeout that restarts itself after changing the image... This code will loop over 6 images with a delay of 5 seconds and that 6 times...
Something like this, perhaps?
var index, imgCount, loopCount, imgTag, countdown;
index = 0;
imgCount = 6;
loopCount = 6;
imgTag = document.getElementById('imgdiv');
countdown = function () {
if (index < imgCount * loopCount) {
imgTag.src = 'images/' + index % imgCount + '.svg';
index = index + 1;
setTimeout(countdown, 5000);
}
};
countdown();
Here we're avoiding the double loop and using modular math (index % imgCount) to get the right file number.
For another question I wrote a nice utility function that has quite a number of uses, but can also handle this scenario very easily. The main issue is that there is no time elapsing between the different delays being set. So you are setting 6 different actions to all happen within 5000ms, and all will occur at the same moment.
Here's my original answer
Here's the utility function for that answer, along with its application to your problem.
function doHeavyTask(params) {
var totalMillisAllotted = params.totalMillisAllotted;
var totalTasks = params.totalTasks;
var tasksPerTick = params.tasksPerTick;
var tasksCompleted = 0;
var totalTicks = Math.ceil(totalTasks / tasksPerTick);
var initialDelay = params.initialDelay;
var interval = null;
if (totalTicks === 0) return;
var doTick = function() {
var totalByEndOfTick = Math.min(tasksCompleted + tasksPerTick, totalTasks);
do {
params.task(tasksCompleted++);
} while(tasksCompleted < totalByEndOfTick);
if (tasksCompleted >= totalTasks) clearInterval(interval);
};
// Tick once immediately, and then as many times as needed using setInterval
if (!initialDelay) doTick();
if (tasksCompleted < totalTicks) interval = setInterval(doTick, totalMillisAllotted / totalTicks);
}
// Do 6 actions over the course of 5000 x 6 milliseconds
doHeavyTask({
totalMillisAllotted: 5000 * 6,
totalTasks: 6,
tasksPerTick: 1,
initialDelay: false, // Controls if the 1st tick should occur immediately
task: function(n) { console.log('Set image to "images/' + (n + 1) + '.svg"'); }
});
You want to do setTimeout().
setTimeout pauses for the millesecond value and then does the code. Where setInterval runs the code every whatever milleseconds.
Yeah, don't do change.setInterval or whatever, it is just setInterval.
An example for you would be this inside the for loop to replace the setInterval function.
setTimeout(imgfile(i+1), 5000);

How to set a delay inside a for loop

So I have a for loop and there is one line of code in there that opens a URL for each other iterations. I would like that line that opens the URL to wait 2 seconds before opening each one. How would I do it?
I tried the setTimeout function, but it iterates through the whole loop instantly after waiting the specified seconds, but I want it to wait for each iteration, not just before the iteration or during the first one.
The structure of my code looks something like this:
function someFunction(){
// do something
for(i = 0; i < range; i++){
//do something
//**open URL**
//do something
}
}
How would I make it wait 2 seconds for every iteration before executing that one specific line where it opens the URL? None of the other questions seem to help me, so I was wondering if anyone could help.
You can use settimeout
function delayedFunction(counter){
counter--;
console.log(counter);
if(counter){
setTimeout(function(){delayedFunction(counter); }, 1000);
}
}
delayedFunction(5);
You cannot do this in a for loop. You can do this with setInterval(). The setInterval() method will continue until clearInterval() is called.
Structure
var interval = setInterval(function() {
var i = 0;
if(i < x) {
...
} else {
clearInterval(interval);
}
}, ms);
Example
var urls = ["url1", "url2", "url3", "url4"];
function showDelayed(arr, ms) {
var i = 0;
var interval = setInterval(function() {
if (i < arr.length) {
// Do something here
console.log(arr[i]);
} else {
clearInterval(interval); // Clear when i === arr.length
}
i += 1; // Interval increments 1
}, ms);
}
showDelayed(urls, 300);
Not that this is a very good practice (opening up multiple URLS on an interval),
but since you asked.
var urlarray = ["https://www.mysite1.com", "https://www.mysite2.com", "https://www.mysite3.com"];
var currentURL = 0;
setInterval(function() {
if (currentURL < urlarray.length) {
alert(urlarray[currentURL]);
}
currentURL++;
}, 1500);

How to create pause or delay in FOR loop?

I am working on a website, where I need to create a pause or delay.
So please tell me How to create pause or delay in for loop in javascript or jQuery
This is a test example
var s = document.getElementById("div1");
for (i = 0; i < 10; i++) {
s.innerHTML = s.innerHTML + i.toString();
//create a pause of 2 seconds.
}
You can't use a delay in the function, because then the change that you do to the element would not show up until you exit the function.
Use the setTimeout to run pieces of code at a later time:
var s = document.getElementById("div1");
for (i = 0; i < 10; i++) {
// create a closure to preserve the value of "i"
(function(i){
window.setTimeout(function(){
s.innerHTML = s.innerHTML + i.toString();
}, i * 2000);
}(i));
}
var wonderfulFunction = function(i) {
var s = document.getElementById("div1"); //you could pass this element as a parameter as well
i = i || 0;
if(i < 10) {
s.innerHTML = s.innerHTML + i.toString();
i++;
//create a pause of 2 seconds.
setTimeout(function() { wonderfulFunction(i) }, 2000);
}
}
//first call
wonderfulFunction(); //or wonderfulFunction(0);
You can't pause javascript code, the whole language is made to work with events, the solution I provided let's you execute the function with some delay, but the execution never stops.
I tried all one, but I think this code is better one, it is very simple code.
var s = document.getElementById("div1");
var i = 0;
setInterval(function () {s.innerHTML = s.innerHTML + i.toString(); i++;}, 2000);
if you want to create pause or delay in FOR loop,the only real method is
while (true) {
if( new Date()-startTime >= 2000) {
break;
}
}
the startTime is the time before you run the while
but this method will cause the browsers become very slow
It is impossible to directly pause a Javascript function within a for loop then later resume at that point.
This is how you should do it
var i = 0;
setTimeout(function() {
s.innerHTML = s.innerHTML + i.toString();
i++;
},2000);
The following code is an example of pseudo-multithreading that you can do in JS, it's roughly an example of how you can delay each iteration of a loop:
var counter = 0;
// A single iteration of your loop
// log the current value of counter as an example
// then wait before doing the next iteration
function printCounter() {
console.log(counter);
counter++;
if (counter < 10)
setTimeout(printCounter, 1000);
}
// Start the loop
printCounter();
While several of the other answers would work, I find the code to be less elegant. The Frame.js library was designed to solve this problem exactly. Using Frame you could do it like this:
var s = document.getElementById("div1");
for (i = 0; i < 10; i++) {
Frame(2000, function(callback){ // each iteration would pause by 2 secs
s.innerHTML = s.innerHTML + i.toString();
callback();
});
}
Frame.start();
In this case, it is nearly the same as the examples that use setTimeout, but Frame offers a lot of advantages, especially if the you are trying to do multiple or nested timeouts, or have a larger JS application that the timeouts need to work within.
I am executing a function where I need access to the outside object properties. So, the closure in Guffa solution doesn't work for me. I found a variation of nicosantangelo solution by simply wrapping the setTimeout in an if statement so it doesn't run forever.
var i = 0;
function test(){
rootObj.arrayOfObj[i].someFunction();
i++;
if( i < rootObj.arrayOfObj.length ){
setTimeout(test, 50 ); //50ms delay
}
}
test();
The way I found was to simply use setInterval() to loop instead. Here's my code example :
var i = 0;
var inte = setInterval(() => {
doSomething();
if (i == 9) clearInterval(inte);
i++;
}, 1000);
function doSomething() {
console.log(i);
};
This loops from 0 to 9 waiting 1 second in between each iteration.
Output :
0 1 2 3 4 5 6 7 8 9
It is not possible to pause a loop. However you can delay the execution of code fragments with the setTimeout() function. It would not make a lot of sense to pause the entire execution anyway.
I am using while loop and check the pause variable to check the user pause/resume the code.
var pause = false;
(async () => {
for (let index = 0; index < 1000; index++) {
while (pause) {
await new Promise((res) => setTimeout(res, 1000));
console.log("waiting");
}
await new Promise((res) => setTimeout(res, 1000));
console.log(index);
}
})();
const pausefunc = async () => {
pause = true;
};
const playfunc = () => {
pause = false;
};
<button onclick="playfunc()">Play</button>
<button onclick="pausefunc()">Pause</button>
I used a do...while loop to put a delay in my code for a modal dialog that was closing too quickly.
your stuff....
var tNow = Date.now();
var dateDiff = 0;
do {
dateDiff = Date.now() - tNow;
} while (dateDiff < 1000); //milliseconds - 2000 = 2 seconds
your stuff....

Can setInterval store a value in a variable

Look at this code
var count = 0, count2 = 0
setInterval(function() {
// I wrote this on two lines for clarity.
++count;
count2 = count;
}, 1000);
if(count2==5)
{
alert('testing script')
}
How come the if statement does not execute when count2 = 5
The problem is: First you only define the logic for the interval and then you check the count2 variable. But in that context the variable has still the value 0.
Each time the interval is fired (and in most cases it is after the if-check), only the part inside the function() { } block is executed
function() {
// I wrote this on two lines for clarity.
++count;
count2 = count;
}
and it is not continued to the if statement because it is not part of the interval logic.
The first idea I have is to put the if statement into the function() { } block like this:
var count = 0, count2 = 0;
setInterval(function() {
// I wrote this on two lines for clarity.
++count;
count2 = count;
if(count2 == 5)
{
alert('testing script');
}
}, 1000);
var count = 0, count2 = 0 // missing semi colon(!)
setInterval(function() { // this function will be executed every 1000 milliseconds, if something else is running at that moment it gets queued up
++count; // pre-increment count
count2 = count; // assign count to count 2
}, 1000);
// ok guess what this runs IMMEDIATELY after the above, and it only runs ONCE so count 2 is still 0
if(count2==5) // DON'T put { on the next line in JS, automatic semi colon insertion will get you at some point
{
alert('testing script')
}
Read a tutorial to get started: https://developer.mozilla.org/en/JavaScript/Guide.
yes it can store a value.
function hello(){
var count = 0;
var timer = setInterval( function(){ count+=1;alert(count); },2000);
}
Try This Out, it works
//Counting By Z M Y.js
if(timer){window.clearInterval(timer)} /*← this code was taped , in order to avoid a sort of bug , i'm not going to mention details about it */
c=0;
do{ w=prompt('precise the number of repetition in which the counting becomes annoying',10)}
while (!(w>0)||w%1!=0)
function Controling_The_Counting(c,w)
{
if(c%w==0&&c>0){return confirm('do you want to continue ?'); }
return true;
}
var timer = setInterval( function(){ console.clear();c+=1;console.log(c); StopTimer() },1000);
function StopTimer() { if(!Controling_The_Counting(c,w)) {window.clearInterval(timer) ;} }

Categories

Resources