inside JavaScript, how can I tell something to be done in a certain period of time? For example, for 5 seconds, the value of a variable will increase and it will stop after 5 seconds. Of course, there are setinterval and settimeout, but they only do that work after that period of time is over. I want that work to be done during that time.
-
You will want to use a loop, but makes sure it's an async loop so it doesn't block the main thread. – Keith Aug 22 '22 at 14:59
-
3There's no built-in time limiter. Use `setInterval()` to repeatedly do parts of the task. Inside that function, check if the time limit has been reached and call `clearInterval()` to stop. – Barmar Aug 22 '22 at 15:02
-
Does this answer your question? [setTimeout or setInterval?](https://stackoverflow.com/questions/729921/settimeout-or-setinterval) – computercarguy Aug 22 '22 at 15:09
3 Answers
setInterval
You can use setInteveral
, but it's mostly trash for everything I've ever attempted to use it for. In the code below, the counter will only increment to around 35 in 1 second; about 28 milliseconds per interval -
// initialize a counter
let counter = 0
// increment the counter on interval
let myprocess = setInterval(_ => counter++, 0)
// after 5 seconds, stop the process and log the counter value
setTimeout(_ => { clearInterval(myprocess); console.log(counter) }, 1000)
A more appropriate utility would be setImmediate. It is supported in Node but not in browsers yet. Polyfills are available if you plan to use this in the browser.
async generators
Above we see setInterval
is quite slow. Another approach is to use an asynchronous generator. In the code below, the counter can reach over 300,000 in just 1 second; About 3.3 microseconds per interval.
async function *count(until) {
let counter = 0
while (Date.now() < until) {
yield counter++
}
}
async function main() {
for await (const n of count(Date.now() + 1000))
document.write(`${n}, `)
return "done"
}
main().then(console.log)
If the goal is to run the process as fast as possible for the fixed duration, we will skip expensive operations like document.write
. In the example below the counter can reach over 1M in just 1 second; just under 1 microsecond per interval -
async function *count(until) {
let counter = 0
while (Date.now() < until) {
yield counter++
}
}
async function run(process, duration) {
let result
for await (const n of process(Date.now() + duration))
result = n
return result
}
run(count, 1000).then(console.log)
// 1045592
blocking while loop
If the loop itself is the main part of your program and you want simply want to run the counter as fast as possible for a fixed duration, use a while
loop. Note this will block all other code from running for the entire duration of the loop -
function count(until) {
let n = 0
while (Date.now() < until)
n++
return n
}
setTimeout(console.log, 0, "I was blocked")
console.log(count(Date.now() + 1000))
// 36618673
// "I was blocked"

- 129,518
- 31
- 228
- 259
-
Nice example :), async generators are really nice, I've been using them for streaming, makes the code much simpler to follow understand.. – Keith Aug 22 '22 at 15:38
-
@Keith I actually made the mistake of thinking the counter generator had to be async. Using a synchronous generator is ludicrously fast. – Mulan Aug 22 '22 at 15:57
-
1It wasn't a mistake, it's faster using simple generators, but now your blocking the Javascript's main thread, try increasing your example to 5 seconds, and use a simple setTimeout for 1 second, you will notice the timeout will not fire :( – Keith Aug 22 '22 at 16:07
-
-
Worth pointing out, you might have noticed if you use the `setTimeout` it still blocks. This is because Promises these days use micro tasks, and until they have been exhausted don't execute normal Tasks,. A simple solution here is say every 100ms or so use a simple promise based sleep in your loop, this will then allow Timeouts & GUI updates to still fire, but yet keep performance high.. – Keith Aug 23 '22 at 10:33
You will need to check inside some sort of loop if the time has passed, make sure the loop is async in nature or the JS main thread will have issues.
I have modified PI calculator from here Javascript: PI (π) Calculator to run for 5 seconds instead of infinite , it's using requestAnimationFrame to keep things async->
function * generateDigitsOfPi() {
let q = 1n;
let r = 180n;
let t = 60n;
let i = 2n;
while (true) {
let digit = ((i * 27n - 12n) * q + r * 5n) / (t * 5n);
yield Number(digit);
let u = i * 3n;
u = (u + 1n) * 3n * (u + 2n);
r = u * 10n * (q * (i * 5n - 2n) + r - t * digit);
q *= 10n * i * (i++ * 2n - 1n);
t *= u;
}
}
// Demo
let iter = generateDigitsOfPi();
const tmStart = Date.now();//
let output = document.querySelector("div");
(function displayNextDigit() {
output.insertAdjacentHTML("beforeend", iter.next().value);
scrollTo(0, document.body.scrollHeight);
if (Date.now() - tmStart < 5000) requestAnimationFrame(displayNextDigit);
})();
div { word-wrap:break-word; font-family: monospace }
<div></div>

- 22,005
- 2
- 27
- 44
-
1
-
Also the Pi calculator is neat. I calculated the first 25,000 digits with it and it's accurate. To your knowledge, will this particular calculator eventually diverge? – Mulan Aug 22 '22 at 16:16
-
@Mulan I have to admit that PI calculator was stolen from the link I posted, trincot then mentions he got the maths for this from -> http://www.cs.ox.ac.uk/jeremy.gibbons/publications/spigot.pdf From what I can gather the limit is only the amount of memory your PC has. – Keith Aug 23 '22 at 09:33
const setRunInSeconds = (callback, ms = 1000, delay = 1) => {
const intervalId = setInterval(callback, delay)
setInterval(() => {
clearInterval(intervalId)
}, ms)
}
let num = 0
setRunInSeconds(() => {
console.log('interval: ' + num)
num += 1
}, 5000, 1)

- 2,186
- 2
- 6
- 21