Web Platform

Timing

See also: To access the current time and date, see Data Types II.

Two in-built functions are useful for constructing a flow of code based on time: setInterval and setTimeout. The functions essentially allow you to schedule when code will run.

Intervals

setInterval will continuously call whatever function you give it at the millisecond interval you set. Examples:

const showMessage = () => { ... omitted ... }
const cuckoo = () => { .. omitted ... }

// Calls 'showMessage' every 10s - 1s = 1000ms
setInterval(showMessage, 10*1000);

// Calls 'cuckoo' every 60 minutes
setInterval(cuckoo, 60*60*1000);

// Runs the anonymous function every second
setInterval(() => {
  console.log("Tick!");
}, 1000);

See live demo

To cancel the interval, you need to keep track of the scheduled execution, and pass this to clearInterval:

// Start
let cuckooInterval = setInterval(cuckoo, 60*60*1000);

// User clicked a 'Stop' button, stop the timer
function onStopClick() {
  clearInterval(cuckooInterval);
}

For practical purposes, you can depend on the scheduled code to run at the interval you specify, but be aware that the timing is not 100% precise. If the Javascript engine is busy with other work, or the device itself is overloaded, execution may be delayed.

Another consideration of setInterval is that it doesn't take into account how long it actually takes your code to run. If you have code scheduled to run every second, but it actually takes five seconds for the code to finish running, you'll end up with lots of overlapped function calls - maybe not what you expect. See the Conditional intervals pattern below for a solution.

Read more

Delays

setTimeout calls a function after a millisecond delay has elapsed. Unlike setInterval, the function only executes once. Examples:

// Calls 'showMessage' after 10 seconds
setTimeout(showMessage, 10*1000);

Use clearTimeout to cancel a scheduled function call, just like with intervals.

let t = setTimeout(showMessage, 2*60*1000);
...
function onSomethingElseHappens() {
  clearTimeout(t);
}

Conditional intervals

A common pattern is for a delayed function call to reschedule itself conditionally. The behaviour thus is like setInterval, but rather than cancelling, you choose not to reschedule it.

The primary benefit of the self-scheduled interval is that it doesn't matter how long it takes your function to run, it will still wait the full delay before executing again.

function moveBox() {
 // do something...

 // Run again if there hasn't been any user interaction
 if (!userInteraction)
  setTimeout(moveBox, 1000); 
}
moveBox(); // start it the first time

Note that calling moveBox() more times will create additional, overlapping execution loops - not normally what you want.

Synchronisation

If you want to synchronise with the actual time - for example to call a function exactly on-the-hour, or on-the-minute, you can calculate the time difference and use that:

// Runs the next time the computer's clock switches to the next minute

// Get seconds returns 0..59 of the current time
// ie, if it's 20, it means it's 20 seconds past the minute,
// and we have to wait 40s until the next minute
const now = new Date();
const nextMinuteInMs = (60-now.getSeconds()) * 1000; 
setTimeout(() => {
  console.log('On the minute! It is now: ' + new Date());
}, nextMinuteInMs);

See live demo

If you then want to keep executing code on-the-minute, we can refactor the code a bit to continually reschedule when to call onTheMinute

const onTheMinute = () => {
  console.log('On the minute! It is now: ' + new Date());  
  schedule(); // Schedule for the next minute
}

const schedule = () => {
  const now = new Date();
  const nextMinuteInMs = (60-now.getSeconds()) * 1000; 

  // Schedule 'onTheMinute' to be called when we're next on an even minute
  setTimeout(() => {
    onTheMinute();
  }, nextMinuteInMs);  
}

// Schedule the first call
schedule();

See live demo

Animation

You can certainly do basic animation with setInterval or setTimeout, even though it's a bad idea.

<body>
  <div style="position:fixed" id="box">
  BOX
  </div>
</body>
const loop = () => {
  const el = document.getElementById('box');
  if (el.offsetLeft >= 1000) return; // Stop at some point
  el.style.left = (el.offsetLeft + 10) + "px"
    setTimeout(loop, 1000);
}
loop();

See live demo

Processing a list

Here's an example of how to process an item from an array every x milliseconds:

const processLoopSlowly = (items, delay) => {
  let position = 0; // Keep track of where we are

  // Define a function within this function
  const loop = () => {
    // Do something with the item here...
    console.log("Processing: " + items[position]);
    position++;
    if (position == items.length) {
      console.log("Finished"); // We're done
    } else {
      setTimeout(loop, delay); // Otherwise, self-scheduled again
    }
  }
  setTimeout(loop, delay);
}

const items = [
  "Passionfruit", "Kiwifruit", "Mango", "Nectarines"
]
processLoopSlowly(items, 1000);

See live demo

More