JavaScript delay before looping - javascript

I am a complete noob at coding and have a quick question. Below is a snipet of code and what I need to do is, if the process repeats (i.e., ctr < end) then I need it to wait for 2 minutes before doing so. I don't want to lock down the computer, this will be running a background task. I have researched and while I might have found a solution in setTimeout(), I can't implement it properly with my limited knowledge. Thanks in advance for your help!
if (ctr < end) {
return function() {
otherFunction(ctr + 1);
};

Basic Example demonstrating setTimeout
var ctr = 0;
var end = 5;
mainLoop();
// some function
function mainLoop() {
// checks current ctr to end then increments ctr by 1
if (ctr++ < end) {
// log the value of ctr
console.log(ctr);
// This is set to happen every 2 seconds
// 2 minutes is 2 * 60 * 1000 = 120000 milliseconds
// calls the mainLoop function after 2000 milliseconds
setTimeout(mainLoop, 2000);
} else {
// prints it is over after the ctr is equal or greater than end
console.log('it is over');
}
}

Related

How to do a countdown with randomized time intervals, stopping at zero?

i would like to add another counter in this code:
function animateValue(id) {
var obj = document.getElementById(id);
var counter = getLocalStoregaValue();
var current = counter ? +counter : obj.innerHTML;
obj.innerHTML = counter;
setInterval(function() {
var counter = current--;
obj.innerHTML = counter;
localStorage.setItem('counter', counter);
}, 1000);
}
function getLocalStoregaValue() {
return localStorage.getItem('counter');
}
animateValue('value');
I would like it to scale once every second (as in this case) and once every 5 seconds. How can I? And then, how can I make it stop at 0? So without negative numbers. Thank you very much.
EDIT: I explained myself wrong.
I would like a single counter that drops in number from a minimum of 10 to a maximum of 20.
Example: the counter marks 50. After 15 seconds it marks 49. After 18 seconds it marks 48. After 11 seconds it marks 47. And so up to 0.
I hope I explained myself well this time :)
Ok, I was interrupted while posting my answer. Here now the explanation:
I left out the localStorage part of your question and concentrated on the generation of "independent countdowns" first:
function cntdwn(sel,stp,intv){
let el=document.querySelector(sel),
n=el.textContent-stp,
cd=setInterval(()=>{
el.textContent=n;
if((n-=stp)<0) clearInterval(cd);
}, intv);
}
cntdwn('#one',1,1000) ;
setTimeout(()=>cntdwn('#two',1,3000), 12000);
<p>first countdown:<br>step: 1, interval: 1s</p>
<p id="one">15</p>
<p>second countdown:<br>step: 1, action after: 15, 18, 21, 24 ... s (as mentioned in comment)</p>
<p id="two">50</p>
The cntdwn() function provides a scope in which individual countdowns can be set up for arbitrary DOM elements, each with their own counter (it starts with the value found in the DOM element), step-width and interval (in milliseconds).
Each countdown is generated with let cd=setInterval(...). The reference cd can then be used to stop the countdown (in clearInterval(cd)), once the value of n is found to be below zero.
Edit:
Assuming you made a typo in your sequence of intervals and you really meant: 15, 18, 21 seconds, then the edited second countdown should be the correct solution.
I used a setTimeout() function to delay the action by 12 seconds, then, after the first of the regular 3 second intervals (i. e. after a total of 15 seconds) the first change occurs. The countdown then continues in 3 second intervals until it reaches zero.
Yet another edit:
Ok, so you want: "A countdown with random time intervals (range 10 to 20s each) that will stop at zero"
This should do it:
function cntdwn(sel,int1,int2){
let el=document.querySelector(sel),
n=el.textContent-1,
cd=()=>setTimeout(()=>{
el.textContent=n;
if(n--) cd();
}, 1000*(int1+Math.random()*(int2-int1)));
cd();
}
cntdwn('#one',10,20);
<p>countdown:<br>step: 1, intervals: between 10 and 20 s</p>
<p id="one">5</p>
If you can use ES2017, you can use an asynchronous function to do it, like this:
async function animateValue(id) {
function timeout(t){
return new Promise(r => setTimeout(r, t))
}
var obj = document.getElementById(id);
var counter = getLocalStoregaValue();
for(let i = +counter || +obj.innerHTML || 0; i >= 0; i--){
obj.innerHTML = i;
localStorage.setItem('counter', i);
await timeout((Math.random() * 10 + 10) * 1000); //Pause for 10 to 20 seconds. For an integer second value, wrap `Math.random() * 10` into a `Math.floor` call
};
}
function getLocalStoregaValue() {
return localStorage.getItem('counter');
}
animateValue('value').catch(console.error);
<div id="value">50</div>
Try it (I commented out the localStorage part, as it isn't allowed in Stack Snippets):
async function animateValue(id) {
function timeout(t){
return new Promise(r => setTimeout(r, t))
}
var obj = document.getElementById(id);
var counter = getLocalStoregaValue();
for(let i = +counter || +obj.innerHTML || 0; i >= 0; i--){
obj.innerHTML = i;
//localStorage.setItem('counter', i);
await timeout((Math.random() * 10 + 10) * 1000); //Pause for 10 to 20 seconds. For an integer second value, wrap `Math.random() * 10` into a `Math.floor` call
};
}
function getLocalStoregaValue() {
//return localStorage.getItem('counter');
}
animateValue('value').catch(console.error);
<div id="value">50</div>

Javascript for loop with settimeout time change

So I'm trying to increase the time out in a for loop, I followed the answer here setTimeout with Loop in JavaScript but the duration of the setTimeout is just not working in milliseconds when I output the date to check the time difference.
Code:
for (var count = 0; count < 12; count++) {
(function(num){setTimeout(function() {
console.log("Count = " + num + " Time: " + 1000 * num + " Stamp: " + new Date());
}, 1000 * num)})(count);
}
As you can see in the console, it's still firing the console.log every 1000 instead of 1000 * count.
I hope the above makes sense and hopefully someone can explain this behaviour.
Is this what you are looking for? Increase the time for each iteration 1second * some count
let i = 0;
loop = () => {
setTimeout(() => {
console.log("Count = " + i + " Time: " + 1000 * i);
i++;
if (i < 10) {
loop();
}
}, i * 1000)
};
loop();
Here is a REPL, you can hit run
Explanation: Try running this code
for (var i = 1; i < 5; i++) {
setTimeout(() => console.log(i), 1000)
}
We would expect the output to be 1 2 3 4 but its actually 5 5 5 5, that's because js runtime engine does not wait for the settimeout to complete instead it passes it onto the web API and it is queued there, so the for loop executes first making i = 5 and at a later point of time the Web API's triggers the set time out function. You can learn about this in detail here.
The code is working as expected.
All the timers are all set almost at the same time as they are async. So, the timers are set and the code continues loading the other timers without waiting for the code to be executed.
The first timer will go off after 1 second.
The second timer will go off after 2 seconds. But two seconds after the timer was set, which is the same time at which the timer 1 was set.
And so on.
So, each timer is firing at 1000 * count.

Run a function for a specified amount of time and stop [duplicate]

I would like to repeat a text for 2 seconds in a while loop. How do I break the loop after 2 seconds?
This is what I have tried so far but it doesn't work:
var repeat = true;
setTimeout(function() { var repeat = false }, 2000)
while(repeat) {
console.log("Let's repeat for 2 seconds...");
}
Additionaly to the other answer you could just check the time instead:
const start = +new Date;
while(+new Date < start + 2000) {
console.log("Let's repeat for 2 seconds...");
}
JavaScript is single threaded. This means that as long as your loop runs, your timeout will never be fired.
Depending on what you want and whether or not you want to lock down your browser (by using an actual infinite loop), you can use the setInterval as a loop, and use the setTimeout to stop the interval after 2 seconds.
console.log("Starting loop");
var interval = setInterval(function () {
console.log("Let's repeat for 2 seconds...");
}, 0);
setTimeout(function() {
clearInterval(interval);
console.log("Finished loop");
}, 2000);
If you're concerned at all with performance of this loop, the proposed solution would be a problem.
Note that in most cases, you shouldn't be synchronously iterating a huge number of times in Javascript since that would completely block the browser or server during this time, but there are some cases where this might be needed. Just be aware that this is generally not a good thing to do.
What follows is my own experimentation with several options to reduce the overhead of checking a timeout, since I was using it to benchmark other code.
I added console.time logs to both solutions, and added a couple of optimizations that might be worth considering.
The accepted solution has the worst performance:
const label = 'interval';
console.time(label);
let i = 0;
const interval = setInterval(
() => {
i += 1;
},
0);
setTimeout(
() => {
clearInterval(interval);
console.timeEnd(label)
console.log(`${i.toExponential()} iterations`);
},
2000);
// interval: 2001.100ms
// 4.93e+2 iterations
The next answer has much better performance, but it's still performing unnecessary work, type conversions and addition on every loop run:
let i = 0;
let start = +new Date;
let label = '+new Date + 2000';
console.time(label);
while ((+new Date) < start + 2000) {
i += 1;
}
console.timeEnd(label)
console.log(`${i.toExponential()} iterations`);
// +new Date + 2000: 1999.800ms
// 1.0921121e+7 iterations
By using Date.now() instead of (+new Date) you get a performance increment of around 2.5x:
let label = 'Date.now()';
console.time(label);
let end = Date.now() + 2000;
let i = 0;
while (Date.now() < end) {
i += 1;
}
console.timeEnd(label)
console.log(`${i.toExponential()} iterations`);
// Date.now(): 1999.000ms
// 2.6477108e+7 iterations
If performance is much more important that the exact nanosecond when you stop, and the operations are super fast, you can reduce the number of checks for even more operations:
let label = 'fuzzy + 2000';
console.time(label);
let end = Date.now() + 2000;
let i = 0;
// Only check the timeout every 1000 operations thanks to lazy evaluation.
while (i % 1000 !== 0 || Date.now() < end) {
i += 1;
}
console.timeEnd(label)
console.log(`${i.toExponential()} iterations`);
// fuzzy + 2000: 1999.800ms
// 6.5632e+8 iterations
30x better! You will need to tweak the frequency of the checks based on both the average loop time and how exact you want your timeout to be.

Leave a loop after 2 seonds

I would like to repeat a text for 2 seconds in a while loop. How do I break the loop after 2 seconds?
This is what I have tried so far but it doesn't work:
var repeat = true;
setTimeout(function() { var repeat = false }, 2000)
while(repeat) {
console.log("Let's repeat for 2 seconds...");
}
Additionaly to the other answer you could just check the time instead:
const start = +new Date;
while(+new Date < start + 2000) {
console.log("Let's repeat for 2 seconds...");
}
JavaScript is single threaded. This means that as long as your loop runs, your timeout will never be fired.
Depending on what you want and whether or not you want to lock down your browser (by using an actual infinite loop), you can use the setInterval as a loop, and use the setTimeout to stop the interval after 2 seconds.
console.log("Starting loop");
var interval = setInterval(function () {
console.log("Let's repeat for 2 seconds...");
}, 0);
setTimeout(function() {
clearInterval(interval);
console.log("Finished loop");
}, 2000);
If you're concerned at all with performance of this loop, the proposed solution would be a problem.
Note that in most cases, you shouldn't be synchronously iterating a huge number of times in Javascript since that would completely block the browser or server during this time, but there are some cases where this might be needed. Just be aware that this is generally not a good thing to do.
What follows is my own experimentation with several options to reduce the overhead of checking a timeout, since I was using it to benchmark other code.
I added console.time logs to both solutions, and added a couple of optimizations that might be worth considering.
The accepted solution has the worst performance:
const label = 'interval';
console.time(label);
let i = 0;
const interval = setInterval(
() => {
i += 1;
},
0);
setTimeout(
() => {
clearInterval(interval);
console.timeEnd(label)
console.log(`${i.toExponential()} iterations`);
},
2000);
// interval: 2001.100ms
// 4.93e+2 iterations
The next answer has much better performance, but it's still performing unnecessary work, type conversions and addition on every loop run:
let i = 0;
let start = +new Date;
let label = '+new Date + 2000';
console.time(label);
while ((+new Date) < start + 2000) {
i += 1;
}
console.timeEnd(label)
console.log(`${i.toExponential()} iterations`);
// +new Date + 2000: 1999.800ms
// 1.0921121e+7 iterations
By using Date.now() instead of (+new Date) you get a performance increment of around 2.5x:
let label = 'Date.now()';
console.time(label);
let end = Date.now() + 2000;
let i = 0;
while (Date.now() < end) {
i += 1;
}
console.timeEnd(label)
console.log(`${i.toExponential()} iterations`);
// Date.now(): 1999.000ms
// 2.6477108e+7 iterations
If performance is much more important that the exact nanosecond when you stop, and the operations are super fast, you can reduce the number of checks for even more operations:
let label = 'fuzzy + 2000';
console.time(label);
let end = Date.now() + 2000;
let i = 0;
// Only check the timeout every 1000 operations thanks to lazy evaluation.
while (i % 1000 !== 0 || Date.now() < end) {
i += 1;
}
console.timeEnd(label)
console.log(`${i.toExponential()} iterations`);
// fuzzy + 2000: 1999.800ms
// 6.5632e+8 iterations
30x better! You will need to tweak the frequency of the checks based on both the average loop time and how exact you want your timeout to be.

Repeating a function with a 1 second interval a certain number of times

So, I'm working on a timer and this is my code right now:
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds) {
break;
}
}
}
function timerCreate() {
for (i = 0; i < 10; i++) {
sleep(1000);
minusOneSec();
}
}
All I wanted to do was that ten times, every one second, the minusOneSec() function was executed. (I took the code for the sleep() function from an answer I saw in StackOverflow some time ago and I don't remember who came up with it so if you know please tell me so I can credit them.) It works, but now it has come to my atention that this sleep function will stop all java script in the page while it's running. Is this true? What I also tried was this:
function timerCreate() {
for (i = 0; i < 10; i++) {
setInterval(minusOneSec, 1000);
}
}
but what it did was to run the minusOneSec() function 10 times in a row, then wait one second, then the function 10 times in a row, and so on. Is there a way to do what I intended but allowing other javascript code to run at the same time? I can use jQuery if necessary.
You need to call setInterval() just once (instead of in a loop) and check the counter inside. setInterval() will keep executing the passed function, till we clear the interval.
var i = 0,
interval = setInterval(function() {
minusOneSec();
i++;
if(i >= 10) clearInterval(interval); // stop it
}, 1000);

Categories

Resources