How can I delay a loop depending on a condition? - javascript

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);
}

Related

How to repeat `setInterval`?

How can i repeat setInterval?
So, i have a function (Duration = 19sec for 1 itteration).
First 4 seconds - label is "text 1",
Next 7 seconds - label is "text 2"
And next 8 seconds - label is "text 3".
And after 19s it should repeat (I have var of itterations - newCurrentElement) and i also have the hole duration of the function (timeNewCurremtElement).
timeNewCurremtElement and newCurrentElement are known, so you shouldn't worry about it.
I have tried to make a loop (for), but that did't work.
function TextChanger() {
counter = 0;
clearInterval(timer);
function TextChanger_Interval(){
timer = setInterval(function() {
counter++;
if (counter <= 3) {
$('#in-hold-out').html("Inhale");
} else if (counter <= 10) {
$('#in-hold-out').html("Hold");
} else if (counter <= 18) {
$('#in-hold-out').html("Exhale");
} else {
counter = 0;
clearInterval(timer);
}
}, 1000);
}
TextChanger_Interval();
}
TextChanger();
Thank you!
You could take an object with the time for changing the text and the text as value.
To illustrate, this example shows unchanged counting as well. if not used, delete the else part.
setInterval((i => () => {
const parts = { 0: 'text1', 4: 'text2', 11: 'text3' };
if (parts[i]) console.log(parts[i]);
else console.log(i);
i++;
i %= 19;
})(0), 1000);
I think you are trying to do something like this
let counter = 0;
function TextChanger() {
if (counter <= 3) {
console.log(0);
} else if (counter <= 10) {
console.log(1);
} else if (counter <= 18) {
console.log(3);
} else {
counter = 0;
}
counter++
}
setInterval(TextChanger, 1000);

Javascript: Waiting for one (or multiple) condition in For Loop

I want to check a condition for k times for a value to be true, inside a For loop, each time I want to wait 2 seconds, after that I want to go next iteration of the for a loop. For example, I tried something like below -
var k = 0;
for (let i = 0; i < B.length; i++) {
setTimeout(function F_stTimer() {
if (B[i].innerText === "S") {
var A = "True"; //just for example
if (A === true && k == 0) {
// Do something
k = k + 1;
i = i - 1; // so , I can check the ith element again once start the loop again
} //if
else if (A === true && k > 0 && k < 5) { //checking 5 times for A to be false
k = k + 1;
}, i * 2000);
i = i - 1;
} //if
else if (A === true && k == 5) {
k = 0;
} //if
} // if
}, 5000);
} // i loop
But the above type of code is not working because I do not change when it is inside setTimeout.
Anyway, can anyone help me with the problem I have?
One does not need to follow the way I mentioned above, what I want to do is-
check a condition for k times for a value to be true, inside a For loop, each time I want wait t seconds (duration of each delay/interval of delay), after that, I want to go next iteration of the for a loop.
Plz comment for further clarification.
You could take an interval and check a counter.
var counter = 0,
interval = setInterval(function () {
counter++;
if (counter === 5) {
counter = 0;
console.log('five');
} else {
console.log('not five');
}
}, 1000);
You could write a function that takes two arguments:
howManyTimes - number of times you want to iterate
howOften - in what intervals you want to do the check (in milliseconds)
function checkInIntervals(howManyTimes, howOften) {
var counter = 0;
var interval = setInterval(function() {
counter++;
if (counter === howManyTimes) {
clearInterval(interval);
}
// do something
console.log(counter, 'iteration')
}, howOften)
}
// run the function
checkInIntervals(10, 2000);
Inside the interval the counter is incremented and when it's equal the the desired number of iterations, the interval is cleared and the execution stops.

Why is my counter function not incrementing?

Basically I wanted to make a countdown with javascript, following my logic the code below should work, but for unknown reason it is not working. Could someone help me to figure out what's wrong with the code? It's kind of annoying.
function startCounter(time)
{
var counter= document.getElementById("counter").innerHTML;
var min=0;
setTimeout(function()
{
for(i = 0; i < time; i++)
{
document.getElementById("counter").innerHTML = min+ ":" +i;
if(i == 59) {
min++;
i = 0
document.getElementById("counter").innerHTML = min+ ":" +i;
}
}
}, 1000)
};
startCounter(89);
<p id="counter">0:00</p>
You are creating an infinite loop.
You are wrapping this part:
if(i == 59) {
min++;
i = 0
document.getElementById("counter").innerHTML = min+ ":" +i;
}
in a for loop that uses i as a limiter. Each time the i reaches 59, you are resetting it back to 0, and the loop continues.
// Add your code here
function startCounter(time)
{
var counter= document.getElementById("counter").innerHTML;
var min = parseInt(time / 60);
var seconds = time % 60;
setInterval(function()
{
seconds++;
document.getElementById("counter").innerHTML = min+ ":" +seconds;
if(seconds == 60) {
min++;
seconds = 0
document.getElementById("counter").innerHTML = min+ ":" +seconds;
}
}, 1000)
};
console.log("Start");
startCounter(89);
<p id="counter">
</p>
The issue is with this line:
for(i=0;i<time;i++) {
You have an infinite loop if your time is > 59, because of this line:
if(i==59){
//snip
i=0
}
Since your function is never finishing setTimeout is never finishing and the browser doesn't appear to be updating your element.
Don't set i back to zero, so your for(true) condition ist always true and your loop can't stop.
function startCounter(time)
{
var counter= document.getElementById("counter").innerHTML;
var min=0;
setTimeout(function()
{
for(i = 0; i < time; i++)
{
document.getElementById("counter").innerHTML = min+ ":" +i;
if(i == 59) {
min++;
document.getElementById("counter").innerHTML = min+ ":" +i;
}
}
}, 1000)
};
startCounter(89);
<p id="counter">0:00</p>
var timer;
var i = 0;
var counter = document.getElementById("counter");
var min = 0;
var targetTime = 5;
function startCounter(){
if(min < targetTime){
if(i == 59){
min++;
i = "00";
} else {
i++;
if (i < 10) {
i = "0"+i;
}
}
counter.innerHTML = min + ":" + i;
} else {
clearInterval(timer);
}
}
timer = setInterval(startCounter, 1000);
<p id="counter"></p>
You have a couple of problems... you seem to be trying to iterate seconds inside the callback that will be executed once every second.
Even if you fixed that code, you're going to have a problem with the fact that setTimeout does not execute exactly at the specified value. It fires whenever the thread can queue the task > the time scheduled. So your timer is going to drift over it's duration.
I'd recommend the below approach. Using a requestAnimationFrame loop (you could also use an interval) check the difference in the JavaScript clock between the time you started and now and then print the difference.
var firstTime;
function startTimer(){
firstTime = Date.now();
runTimer();
}
function runTimer(){
var diff = Date.now() - firstTime;//value in milliseconds since the timer started.
var sec = Math.floor((diff/1000)) % 60;//constrain to seconds
var min = Math.floor(diff/(1000 * 60));//minutes
document.getElementById('timer').innerHTML = min + ":"+(String(sec)).padStart(2,"0");
requestAnimationFrame(runTimer);
}
startTimer();
<div id="timer">0:00</div>
You have a couple options that would work. Calling the startCounter again from inside your setTimeout function or my favourite way is window.setInterval.
var p = document.getElementById("count");
function startTimer(time){
var num = 0; // the increment number
var intervalId = window.setInterval(function(){
num += 1; // increment the number
if(num == time){
window.clearInterval(intervalId);
// you can run your callback here after the timer reached your goal
startTimer(num + 1); // this just adds a second and restarts the timer as a example
}
p.innerText = num;
}, 1000);
}
// Start the timer here
startTimer(10);
<p id="count"></p>

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).

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().

Categories

Resources