How can I use setInterval and clearInterval?
Asked Answered
Q

6

191

Consider:

function doKeyDown(event) {
    switch (event.keyCode) {
    case 32:
        /* Space bar was pressed */
        if (x == 4) {
            setInterval(drawAll, 20);
        }
        else {
            setInterval(drawAll, 20);
            x += dx;
        }
        break;
    }
}

I want to call drawAll() once, not creating a loop that call drawAll again and again. Should I use a recursive method for that or should I use clearInterval?

How can I use clearInterval?

Quent answered 12/5, 2011 at 13:14 Comment(0)
H
287

setInterval sets up a recurring timer. It returns a handle that you can pass into clearInterval to stop it from firing:

var handle = setInterval(drawAll, 20);

// When you want to cancel it:
clearInterval(handle);
handle = 0; // I just do this so I know I've cleared the interval

On browsers, the handle is guaranteed to be a number that isn't equal to 0; therefore, 0 makes a handy flag value for "no timer set". (Other platforms may return other values; Node.js's timer functions return an object, for instance.)

To schedule a function to only fire once, use setTimeout instead. It won't keep firing. (It also returns a handle you can use to cancel it via clearTimeout before it fires that one time if appropriate.)

setTimeout(drawAll, 20);
Homeostasis answered 12/5, 2011 at 13:18 Comment(0)
C
44

clearInterval is one option:

var interval = setInterval(doStuff, 2000); // 2000 ms = start after 2sec 
function doStuff() {
  alert('this is a 2 second warning');
  clearInterval(interval);
}
Clepsydra answered 12/5, 2011 at 13:17 Comment(0)
G
17

Side note – if you want to use separate functions to set & clear interval, the interval variable have to be accessible for all of them, in 'relative global', or 'one level up' scope:

var interval = null;    

function startStuff(func, time) {
    interval = setInterval(func, time);
}

function stopStuff() {
    clearInterval(interval);
}
Gesticulate answered 23/11, 2017 at 12:33 Comment(0)
B
12

I used Angular with Electron.

In my case, setInterval returns a Node.js Timer object. Which, when I called clearInterval(timerobject), did not work.

I had to get the id first and call clearInterval:

clearInterval(timerobject._id)

Barbados answered 21/1, 2018 at 16:16 Comment(0)
A
9

Use setTimeout(drawAll, 20) instead. That only executes the function once.

Anastasiaanastasie answered 12/5, 2011 at 13:15 Comment(2)
Thanks a lot, but setTimeout is finishing the loop at each point, I use other approach and its working fine, function doKeyDown(event) { switch (event.keyCode) { case 32: /* Space bar was pressed */ loop = setInterval(drawAll, 20); if (x == 202) { x = 400; spinner(); } break; } }Quent
it wasn't the question thoPrudi
M
0

If we have to use timers, it's best to use setTimeout instead of setInterval.

This way the memory consumption stays low, and browser tabs won't freeze much overtime.

However there is an issue: the loops are not well cadenced, the next loop does run after all tasks completed. See the time loops are not equal and are increasing, little by little:

enter image description here

const timer = setTimeout(function tick(){
  console.log("Hi!")
  // <-- More jobs here -->
  setTimeout(tick, 2000);
}, 2000);

We wouldn't try to create some music in this manner.


A proper more modern way is to NOT use interval or timeout at all, but instead to continuously check the date epoch and proceed accordingly.

To do so, we can use requestAnimationFrame.

In this example, the next loop will be triggered AFTER all functions complete.

This does replace setInterval very well and is more flexible, however this is still not optimal regarding the cadence, after many loops, the intervals are still shifting!!!

/* Countdown loop ----------------------------------------*/
let job = null, origin = new Date().getTime()
const timer = () => {
  if (new Date().getTime() - 2000 > origin){
   console.log("Hi!")
   origin = new Date().getTime()
   job = requestAnimationFrame(timer)
  } else {
      requestAnimationFrame(timer)    
  }
}

/* Start looping -----------------------------------------*/
requestAnimationFrame(timer)

To completely solve both issues:

The loops are well cadenced, and we don't bother with setInterval any more. Every devices will adapt, they will just slow down their animationFrame rate at their own cadence, but still be on time.

enter image description here

/* Timer loop ----------------------------------------*/
let job, origin = new Date().getTime(), i = 0;
const timer = () => {
  if (new Date().getTime() - i > origin){
   console.log("Hi!")
   i = i + 2000
   job = requestAnimationFrame(timer)
  } else if (job !== null){
      requestAnimationFrame(timer)    
  }
}

/* Start looping or start again ------------------------*/
requestAnimationFrame(timer)
// Stop the loop
// job = null
Monoplane answered 15/8, 2023 at 16:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.