Looping through setTimeout function - javascript

I'm trying to write a function which loops x times (3 in this example) through x steps (Step 1, Step 2 in this example) for x seconds (in this example, Step 1 takes 2 seconds, Step 2 takes 1 second).
So I'd like it to loop as below:
Step 1 (2 seconds)
Step 2 (1 second)
Step 1 (2 seconds)
Step 2 (1 second)
Step 1 (2 seconds)
Step 2 (1 second)
I've got the below code, but it only iterates through the loop once, and I can't work out why.
jQuery('input').click(function () {
for(i = 0; i < 3; i++){
jQuery('div').html('Step 1');
setTimeout(function() {
jQuery('div').html('Step 2');
},2000);
setTimeout(function() {
jQuery('div').empty();
},2000 + 1000);
}
});
I would like the loop to continue with the same timings, but go back to the beginning after it hits .empty();.
JSFiddle: http://jsfiddle.net/kmyjhgvd/

The loop iterates 3 times, but the timeouts are always the same: 2000 and 3000, so you have created 3 identical callbacks to be executed in 2 seconds and other 3 ones to be called in three seconds. Here you have what you want, with 6 different timeouts:
http://jsfiddle.net/nsg7ny7L/1/
jQuery('input').click(function () {
var time=0;
for(i = 0; i < 3; i++){
setTimeout(function() {
jQuery('div').html('Step 1');
},time++*1000);
setTimeout(function() {
jQuery('div').html('Step 2');
},time++*1000);
}
setTimeout(function() {
jQuery('div').empty();
},time++*1000);
});
PS: Make sure you understand how it works: JS is singlethreaded, so the for loop calls setTimeout 6 times in a row... the starting time is almost the same for all of them

I have not tried the code, but I think this should work
jQuery('input').click(function () {
loopAction (3, 1, 2); // x is number of loops - s1, s2 in seconds
});
function loopAction(x, s1, s2){
If (x>0){ // as long as x>0 start the iteration
jQuery('div').html('Step 1');
setTimeout(function() {
jQuery('div').html('Step 2');
setTimeout(function() {
loopAction(x-1, s1, s2); // recursive call to self
}, s2*1000);
},s1*1000);
} else {
jQuery('div').empty(); // x>0 is false
}
}

Right now you have step 1 directly in the loop without a timeout, so all three step 1 occurences will happen right away. Then you have step 2 in a timeout, but all three of those have the same time delay so they will all happen at once two seconds later. You get this at different times:
0: Step 1 (i = 0)
0: Step 1 (i = 1)
0: Step 1 (i = 2)
2000: Step 2 (i = 0)
2000: Step 2 (i = 1)
2000: Step 2 (i = 2)
3000: empty (i = 0)
3000: empty (i = 1)
3000: empty (i = 2)
You would want this:
0: Step 1 (i = 0)
2000: Step 2 (i = 0)
3000: Step 1 (i = 1)
5000: Step 2 (i = 1)
6000: Step 1 (i = 2)
8000: Step 2 (i = 2)
9000: empty
Put step 1 and step 2 in timeouts, and set the time delays so that they happen after each other, i.e. using i * 3000 as offset. Then you can empty the element in a separate timeout after the last step:
jQuery('input').click(function () {
for(i = 0; i < 3; i++){
setTimeout(function() {
jQuery('div').html('Step 1');
}, i * 3000);
setTimeout(function() {
jQuery('div').html('Step 2');
}, i * 3000 + 2000);
}
setTimeout(function() {
jQuery('div').empty();
}, 6000 + 3000);
});

jQuery('input').click(function () {
var times = 0,
printStep1 = function(){
JQuery('div').html('Step 1');
setTimeout( printStep2, 1000 );
},
printStep2 = function(){
JQuery('div').html('Step 2');
if( times++ < 3 ) setTimeout( printStep1, 1000 );
};
printStep1();
});
Without JQuery:
document.querySelector('input').addEventListener( "click", function () {
var times = 0,
printStep1 = function(){
document.querySelector('div').innerHTML = 'Step 1';
setTimeout( printStep2, 1000 );
},
printStep2 = function(){
document.querySelector('div').innerHTML = 'Step 2';
if( times++ < 3 ) setTimeout( printStep1, 1000 );
};
printStep1();
});

Generic method to execute a list of steps consecutively with timeouts:
var steps = [
{
timeout: 2000,
action: function() { jQuery('div').html('Step 1'); },
},
{
timeout: 1000,
action: function() { jQuery('div').html('Step 2'); },
},
{
timeout: 1000,
action: function() { jQuery('div').empty(); },
}
];
function executeSteps(times, index) {
index = index || 0;
var task = steps[index];
if(index > 0 || times > 0) {
if(index == 0) times--;
task.action();
setTimeout(function() {
executeSteps(times, (index + 1) % steps.length);
}, task.timeout);
}
}
jQuery('input').click(function () {
executeSteps(3);
});
JSFiddle

Recursive Method answer:
function recursiveSteps(config) {
var _step = config.step;
config.step++;
jQuery('div').html('Step 1');
setTimeout(function() {
jQuery('div').html('Step 2');
},2000);
setTimeout(function() {
jQuery('div').empty();
},3000);
if(config.step < 3) setTimeout(function() {recursiveSteps(config);}, config.step*1000);
//you could put an "end" step here if needed
}
jQuery('input').click(recursiveSteps);

Related

print number from 1 to 10 after every 2 seconds

i want to print number after every n number of seconds and based on few conditions i am changing the timer as well as i am stopping the print function. i have done like this --
var myfunc = {
value : 1,
running : false,
timer : 1000,
start : function(){
this.running = true;
clearInterval(this.timeout);
this.timeout = setTimeout(function() {
myfunc.execute(myfunc);
}, myfunc.timer);
},
execute : function(){
if(!this.running) return false;
console.log( 'Currently at -- ' + (this.value++) );
if (this.value > 5 ){
this.changetiming();
}
if (this.value > 10 ){
this.stop();
return;
}else{
this.start();
}
},
changetiming : function(){
this.timer = 3000;
},
stop : function(){
this.running = false;
clearTimeout(this.timeout);
}
};
myfunc.start();
Now i want to know what is wrong with following code --
for(var i = 0; i <= 10; i++){
print(i);
}
function print(i){
setTimeout(function(){
console.log(i)
},2000);
}
here is the right way and easy way to do this in ES6+:
const printNumbersForEvery2Sec = (n)=>{
for (let i = 1; i <= n; i++) {
setTimeout( () =>{
console.log(i)
}, i * 2000)
}
}
printNumbersForEvery2Sec(10);
by multiplying i , each setTimeout() to be delayed 2 to 20 seconds (2000 x 1, 2000 x 2…) respectively.
I'm pretty sure the question "Why does this JavaScript code
for (var i = 0; i <= 10; i++){
print(i);
}
function print(i) {
setTimeout(function(){
console.log(i)
},2000);
}
print out the values 1 through 10 at once, after 2 seconds have elapsed?" has been asked before.
It is a common mistake.
What you are doing is calling print 10 times. Each call to print takes only a few microseconds. Why? Because it just calls setTimeout. Executing setTimeout takes only a few microseconds to complete. All the call does is schedule something to take place in the future. So within a few microseconds you have scheduled 10 things to take place at about 2 seconds in the future. All the schedulings happen at about the same time. So all the console logs take place at about the same time, two seconds after you scheduled them.
See Satapal's comment to your question for a nice way to do what you want to do.
#easiestway
for (var i = 0; i <= 10; i++){
print(i);
}
function print(i) {
setTimeout(function(){
console.log(i)
},i*2000);
}
Using IIFE, Clouser, and Global Scoping
(function(numbers){
for(var i=0; i<numbers.length; i++){
(function(i){
setTimeout(console.log, i*2000, i+1)
})(i);
}
})(new Array(10))
OR IIFE and Local Scoping
(function(numbers){
for(let i=0; i<numbers.length; i++){
setTimeout(console.log, i*2000, i+1)
}
})(new Array(10))
for(var i = 0 ; i <= 10 ; i++) {
setTimeout( () => { console.log(i) }, i * 1000 );
}
Why we are not able to print 0 to 10 no with the help of var?
Why we are able to do with let?
You might want to try this:
const printNumbersForEvery2Sec = (n)=>{
for (let i = 1; i <= n; i++) setTimeout(console.log, i * 1000,i)
}
printNumbersForEvery2Sec(10);```
You can use timeout of javascript
function timer(n) {
for (let i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i);
}, i * n);
}
}
timer(2000);
In the above code timing is not coded so you can decide how much interval you want.
A more generalised solution:
function printNumbers(start, end, delay=1){
const interval = delay*1000
for(let i=start; i<=end; i++){
setTimeout(console.log, (i-start)*interval, i)
}
}
printNumbers(3, 10, 2) // firstNumber, lastNumber, timeInSeconds
for (let i = 1; i <= 10; i++) {
setTimeout(() => {
console.log(i)
}, (i * 2000) )
}
Far best! and easy solution... Checkout snippet...
for (let i = 1; i <= 10; i++) {
setTimeout(() => {
console.log(i)
}, (i * 2000) )
}
const RandomUnderHundredNumber = (min,max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min; /*min and max numbers are included */
}
let inter
const testFunction = () => {
inter = setInterval(() => console.log(RandomUnderHundredNumber(0,99)), 1000) // generate number between 0 and 99 every 1 sec
}
testFunction();
setTimeout(function( ) { clearInterval(inter); }, 5000); /* clear interval after 5 sec delay (optional) */
const printNumbersForEvery2Sec = (n)=>{
for (let i = 1; i <= n; i++) {
setTimeout( () =>{
console.log(i)
}, i * 2000)
}
}
printNumbersForEvery2Sec(10);
There are two solution to this problem.
Using let keyword, local scope.
const printNumbers = (n) => {
for (let i = 1; i <= n; i++) {
setTimeout( () => {
console.log(i);
}, i * 2000);
}
}
printNumbers(5);
Using var keyword, functional scope with the help of closures.
Wrap the setTimeout function with another function which has the value of the variable at that instance. Which console's log the correct value.
Example is shown below.
const printNumbers = (n) => {
for (var i = 1; i <= n; i++) {
function helper(num){
setTimeout( () => {
console.log(num);
}, num * 2000);
}
helper(i);
}
}
printNumbers(5);

how to print value regular interval of time?

I am using closure in java script to print 1-10 value after each 2 sec.In other words first print 1 then wait for two second then print 2 .I used closure but nothing work .
Here is my code.
for (var i = 0; i < 10; i++) {
(function (index) {
setTimeout(function () {
console.log(i);
}, 2000);
})(i);
}
Use setInterval:
function loopWithDelay(callback, delay, max, min) {
var i = min || 0;
if (i <= max) {
var id = setInterval(function() {
callback(i);
if (++i > max) clearInterval(id);
}, delay);
}
}
loopWithDelay(function(i) { console.log(i) }, 2000, 10);
Or use a recursive setTimeout:
function loopWithDelay(callback, delay, max, min) {
var i = min || 0;
if (i <= max) {
setTimeout(function() {
callback(i);
loopWithDelay(callback, delay, max, ++i);
}, delay);
}
}
loopWithDelay(function(i) { console.log(i) }, 2000, 10);
Instead of using setInterval, you can make a function that call itself using setTimeout
(function myFunc(index) {
setTimeout(function() {
console.log(index);
if (index < 10) myFunc(++index);
}, 2000)
})(1);
Please check below snippet.
var i=1;
var interval = setInterval(function(){
if(i<11){
console.log(i);
i++;
}else{
clearInterval(interval);
}
},2000);
You can create a function for it and use recursive setTimeout calls.
function printDelay(current, last, delay) {
console.log(current);
if(++current <= last) {
setTimeout(function() {
print(current, last, delay);
}, delay);
}
}
printDelay(1, 10, 2000);
One option that hasn't been presented here, and one that will probably get closest to executing "on-time," would be to just set all your timeouts at the same time, each having the desired delay before execution. If you have a smaller, fixed number, this should be fine.
for (var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i + 1); // Add 1 to i for display purposes
}, (i + 1) * 2000); // Execute every 2 seconds starting at 2 seconds
}
This is essentially the same as:
for (var i = 1; i <= 10; i++) {
setTimeout(function() {
console.log(i);
}, i * 2000); // Execute every 2 seconds starting at 2 seconds
}
To start immediately instead of after 2 seconds, the first timeout value just has to come at 0 instead of 2000 (milliseconds).

How can I delay a loop depending on a condition?

I want to create a delay in a loop depending on a condition. Say, I have this:
var maxLoops = 50;
var counter = 0;
(function next() {
if (counter++ >= maxLoops) {
return;
}
setTimeout(function() {
console.log(counter);
next();
}, 100);
})();
Is there any way to pause the process for 2 seconds only when the counter is equal to 10, 20 or 30? So it should print:
1....10
(delay for a custom period of time)
11....20
(delay for a custom period of time)
21....30
(delay for a custom period of time)
31...50
The bottom line is, I don't want to delay at all when the counter isn't equal to 10, 20, 30.
Sure you can do that just change the timeout when you have a multiple of 10.
var maxLoops = 50;
var counter = 0;
(function next() {
counter += 1
var timeout_duration = counter % 10 == 0 ? 2000 : 0;
if (counter >= maxLoops) {
return;
}
setTimeout(function() {
console.log(counter);
next();
}, timeout_duration);
})();
That said, there need some few improvments because maxLoops and counter are defined on the global scope. Make it a function.
function loop (maxLoops, start) {
var counter = start || 0;
(function next() {
counter += 1
var timeout_duration = counter % 10 == 0 ? 2000 : 100;
if (counter >= maxLoops) {
return;
}
setTimeout(function() {
console.log(counter);
next();
}, timeout_duration);
})();
}
loop(50);
If you don't want to call next when counter isn't a multiple of 10, then you can add a usual loop in between the calls.
function loop (maxLoops, start) {
var counter = start || 0;
var timeout_duration = 2000;
(function next() {
while(counter < maxLoops && counter % 10 != 0) {
counter += 1
}
if (counter >= maxLoops) {
return;
}
setTimeout(function() {
console.log(counter);
next();
}, timeout_duration);
})();
}
loop(50);
That said, keep in mind that a setTimeout of 2000 doesn't mean exactly 2 seconds, but not less than 2 seconds. If somehwere, there is a loop that breaks the thread, the setTimeout could be never called as Javascript is single threaded and there is no fact that the function will be called after 2 seconds. If you're planning to use setTimeout to measure something within time, you might have to plan something else that will include the Date object for timings.
You can just use the setTimeout() with a different timing based on your counter:
var maxLoops = 50;
var counter = 0;
(function next() {
if (counter++ >= maxLoops) {
return;
}
var delay = 0;
// on multiples of 10, use a longer counter
if (counter % 10 === 0) {
delay = 2000;
}
setTimeout(function() {
console.log(counter);
next();
}, delay);
})();
Or, you could skip the setTimeout() completely when you don't need the delay.
var maxLoops = 50;
var counter = 0;
(function next() {
if (counter++ >= maxLoops) {
return;
}
// on multiples of 10, use a longer counter
if (counter % 10 === 0) {
setTimeout(function() {
console.log(counter);
next();
}, 2000);
} else {
console.log(counter);
next();
}
})();
Or, rather than recursion, you can just use a while loop as in this working snippet:
var maxLoops = 50;
var counter = 0;
(function next() {
// while we haven't hit maxLoops and while not a multiple of 10
while (counter < maxLoops && counter % 10 !== 0 && counter !== 0) {
log(counter);
++counter;
}
if (counter < maxLoops) {
setTimeout(function() {
log(counter);
++counter;
next();
}, 1000);
}
})();
function log(x) {
var div = document.createElement("span");
div.innerHTML = x + " ";
document.body.appendChild(div);
}

Javascript check counter and repeat function

I have an html page and I'm using JavaScript to create a function that display 2 images (the first between second 5 and second 10 and the second image between second 10 and second 20) and repeat that every 30 seconds.
I tried
var cmp=0
function main() {
window.setTimeout(main,30000);
cmp+1;
if (cmp >= 5 and cmp < 10)
show_image_1 ();
if (cmp >= 10 and cmp < 15)
show_image_2 ();
}
but I didn't find out how to check the time every second.
Define an Interval, and then display the image based on that:
window.setInterval(updateImg, 1000);
var timer = 0;
var imageSrc = document.getElementById("imageSrc");
imageSrc.style.display = "none";
function updateImg() {
timer += 1;
if (timer > 30) {
timer = 0;
}
if (timer >= 5 && timer <= 10) {
imageSrc.style.display = "block";
imageSrc.src = "http://lorempicsum.com/futurama/255/200/1";
} else if (timer >= 10 && timer <= 20) {
imageSrc.style.display = "block";
imageSrc.src = "http://lorempicsum.com/futurama/255/200/2";
} else {
imageSrc.style.display = "none";
}
}
<img src="" id="imageSrc">
JsFiddle: http://jsfiddle.net/ghorg12110/z6vfn1nb/
Here is my proposal:
// Define the images and the duration of each one in seconds (a missing "src" means the image will be empty):
var steps=[
{duration: 2},
{duration: 3, src:'one.jpg'},
{duration: 5, src:'two.jpg'},
{duration: 5},
];
// Index of current step: Will cylce from 0 to steps.length:
var currentStep=0;
// Periodic function to show the current step, and re-invokes itself cyclically:
function nextStep()
{
var step=steps[currentStep];
var img=document.getElementById("myimg");
if (step.src)
{
img.src=step.src;
img.style.visibility="visible";
}
else
{
// When there is no "src" in the current step: Hide the image:
img.style.visibility="hidden";
}
currentStep=(++currentStep % steps.length);
setTimeout(nextStep, 1000*step.duration);
}
To start the cycle, you have to call nextStep().

repeating for loop in javascript

I want to count from 0 to 199 three times in a row in 10 millisecond steps like 0 1 2 ... 198 199 0 1 2 .... 198 199 0 1 2 .... The first run is working fine with:
function count() {
time = 0;
for (var i = 0; i < 200; i++) {
time += 10;
setTimeout(function(j) {
return function() {
console.log(j);
}
}(i), time);
};
};
count();
but i do not get the desired result when calling the function three times like
for (var i = 0; i < 3; i++) {
count();
}
What is the right way for me?
I suppose that should be timed too:
for (var i = 0; i < 3; i++) {
setTimeout(animateRio /*or do you mean count?*/, i*2000);
}
You don't need to schedule all of your own timeouts, setInterval can call a function every unit of time. So create an interval that will run every 10 milliseconds. Then add a loop counter and use some modulo arithmetic.
var time = -1,
interval,
loop = 3;
interval = setInterval(function() {
time += 1;
if(time % 200 === 0) {
loop--;
}
if(loop < 0){
clearInterval(interval);
return;
}
console.log(time % 200);
}, 10);
JSFiddle

Categories

Resources