DEV Community

Cover image for JavaScript recurring timers with setInterval
Chris Bongers
Chris Bongers

Posted on • Updated on • Originally published at daily-dev-tips.com

JavaScript recurring timers with setInterval

Now that we have a good understanding of how JavaScript setTimeout works to delay a function.

Let's look at how we can perform an action every x time.

This can be super helpful for animating stuff or checking a data feed.

JavaScript setInterval function

Let's look at how this will work in its most basic form.

setInterval(() => {
  // Run every 100 milliseconds
}, 100);
Enter fullscreen mode Exit fullscreen mode

This function will run every 100 milliseconds.

Often you might want to achieve this to run only until a specific condition is met.

We can clear the interval by using the clearInterval.

const timer = setInterval(() => {
  // Do something
}, 100);

clearInterval(timer);
Enter fullscreen mode Exit fullscreen mode

Or you can even stop it from inside the interval.

const timer = setInterval(() => {
  if (condition) {
    clearInterval(timer);
    return;
  }

  // Execute the function
}, 100);
Enter fullscreen mode Exit fullscreen mode

This is a great way to stop a particular action from running.

Attention points

When you use setInterval, it does not care how long your function runs.

Meaning it will always start a new loop at the set time.

For example, when you use it to animate, but the animations have different lengths, it might cause weird side-effects where the following animation will start, and the first one only just finished.

setInterval example

As you can see, each function can have its own time to execute.

If you find yourself needing them to wait a specific time, using setTimeout might be a better solution.

We can set up a recursive setTimeout function.
That is a function that calls itself once it's done doing its thing.

const coolFunc = () => {
  // Execute the function

  setTimeout(coolFunc, 100);
};

setTimeout(coolFunc, 100);
Enter fullscreen mode Exit fullscreen mode

Which will result in the following flow.

Set Timeout recursive

If you are keen to see some more real-world examples, here is a list of articles using them.

Thank you for reading, and let's connect!

Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter

Discussion (6)

Collapse
lexlohr profile image
Alex Lohr

One interesting property of setInterval is that there's no guarantee your code will run. For example, the minimal actual resolution in most browsers will be around 17ms, roughly the time an animation frame needs. While you can request smaller values, don't expect your callback to run more often. Also, when a page's tab is in the background, intervals might get suspended and resumed once the page is back in focus.

Collapse
dailydevtips1 profile image
Chris Bongers Author

Oh that's interesting, wan't aware of that actually 👀

Collapse
peerreynders profile image
peerreynders

meaning they can overlap and cause issues.

Function executions don't overlap—they just pile up. An interval of 100 may suggest starting times around 100, 200, 300, and 400 but the reality is that setInterval can continue to queue up work faster than the work can be processed. So the work actually starts at 100, 250, 350, and 550 (or even later if in between interval tasks the event loop processes some other events, promises resolve etc.).

function runBurner() {
  let i = 0;
  const log = makeLogger(document.timeline.currentTime);

  function doWork(pass) {
    switch (pass) {
      case 1:
      case 3:
        burnThread(100);
        return pass > 1;

      case 0:
        burnThread(150);
        return false;

      case 2:
        burnThread(200);
        return false;
    }
    return true;
  }

  function burner() {
    const pass = i++;

    log('entry', pass);
    const done = doWork(pass);
    log('exit', pass);

    if (done) clearInterval(intervalID);
  }

  const intervalID = setInterval(burner, 100);
}

runBurner();

/*
  Something like:

   entry(0): 114.58ms
    exit(0): 265.08ms
   entry(1): 265.38ms
    exit(1): 365.08ms
   entry(2): 365.88ms
    exit(2): 568.08ms
   entry(3): 568.28ms
    exit(3): 668.08ms
 */

//---
function burnThread(t) {
  const start = Date.now();
  while (Date.now() - start < t);
}

function makeLogger(start) {
  const nf = new Intl.NumberFormat(navigator.languages, {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
    style: 'unit',
    unitDisplay: 'narrow',
    unit: 'millisecond',
  });

  return (name, count) => {
    const label = `${name}(${count})`.toString().padStart(8, ' ');
    const time = nf.format(performance.now() - start).padStart(8, ' ');
    console.log(`${label}: ${time}`);
  };
}
Enter fullscreen mode Exit fullscreen mode

The "overlapping animation" scenario could happen with concurrent but distinct animations stepping recursively through requestAnmationFrame() but there each animation step is a separately scheduled function - the entire animation isn't one single continuously running function.

Collapse
dailydevtips1 profile image
Chris Bongers Author

Ah yes, but for your eyes it would cause overlap depending on your animations ofcourse.
It would pile up and freak out, which is rarely what you'll want.

Thanks for the detailed explanation here :)

Collapse
kirankamath96 profile image
Kiran Kamath

I once used *setInterval() * for checking new notifications in application , it comes way handy to make a request call to server continuously after a interval and check for any new notification in database ,

Collapse
curiousdev profile image
CuriousDev

It is possibly worth noting, that these functions also exist with Node with a different implementation (behaviour should be the same).