CSE 154

Lecture 10: Timers

Agenda

JSDoc

Timers

Reminders and Administrivia

CP2 due Wednesday at 11 pm PST

JSDoc

Format for documentation comments in your code

/**
 * Returns the element that has the ID attribute with the specified value.
 * @param {string} idName - element ID
 * @returns {object} DOM object associated with id.
 */
function id(idName) {
  return document.getElementById(idName);
}

JS

Required for all functions in your JS files (see the CQG)

Timers

Animations in Programs

In programs, we often want to repeat some behavior - what can we do to repeat some behavior N times? (loops!)

In simple Java/Python programs, there isn't usually motivation to delay code execution

On webpages with JavaScript, there is often motivation to delay or repeat behavior every X seconds

  • What are some examples you can think of?

Counting Down: A Classic Loop Problem

function startCountDown() {
  let count = 10;
  for (let i = count; i > 0; i--) {
    console.log(i + "...");
  }
  console.log("0!");
}

JS

This prints a countdown to the console as soon as it's called. But what if we want to delay each line printed by 1 second?

Timers

Delaying and/or repeating functions with setTimeout/setInterval

Setting a Timer

function description
setTimeout(responseFn, delayMS) Arranges to call given function after given delayMS, returns timer id
setInterval(responseFn, delayMS) Arranges to call function repeatedly every delayMS ms, returns timer id
clearTimeout(timerID)
clearInterval(timerID)
Stops the given timer

Both setTimeout and setInterval return an ID representing the timer

  • This is not the same as a DOM id! It's a unique identifier the window has access to in order to manage the page timers.
  • If you have access to the id, you can tell the window to stop that particular timer by passing it to clearTimeout/Interval later (e.g. when clicking a "stop timer" button)

Practice: timers-practice.html

setTimeout Example

<button id="demo-btn">Click me!</button>
<span id="output-text"></span>

HTML

function init() {
  id("demo-btn").addEventListener("click", delayedMessage);
}

function delayedMessage() {
  id("output-text").textContent = "Wait for it...";
  setTimeout(sayHello, 3000);
}

function sayHello() { // called when the timer goes off
  id("output-text").textContent = "Hello!";
}

JS

output (full example page)

setInterval Example

<button id="demo-btn">Click me!</button>
<span id="output-text"></span>

HTML

let timerId = null; // stores ID of interval timer
function repeatedMessage() {
  timerId = setInterval(sayHello, 1000);
}

function sayHello() {
  id("output-text").textContent += "Hello!";
}

JS

output (full example page)

More details on timerId variable on slide below

Motivating the timerId variable

  • We sometimes need to keep track of our timer(s) when managing them between functions so we can use clearInterval/clearTimeout or know if we have a timer already running on our page.
  • When we can't keep track of them as local variables, it is good practice to store them as module-global variables (within the scope of the module pattern, but accessible to all functions in your program).
  • These examples will assume we are writing inside a module pattern for brevity, but you can refer to the full examples (linked on slides).

"Toggling" Animation with clearInterval

<button id="toggle-btn">Start/Stop<button>

HTML

let timerId = null; // stores ID of interval timer
function init() {
  id("toggle-btn").addEventListener("click", toggleMessageInterval);
}

// 1. What does this function do?
function toggleMessageInterval() {
  if (timerId === null) {
    timerId = setInterval(sayHello, 1000);
  } else {
    clearInterval(timerId);
    timerId = null; // 2. Why is this line important?
    // 3. What happens if you swap the two lines above?
  }
}

function sayHello() {
  id("output-text").textContent += "Hello!";
}

JS

output (full example page)

Passing Additional Parameters to setTimeout/setInterval

function delayedMultiply() {
  // 6 and 7 are passed to multiply when timer goes off
  setTimeout(multiply, 2000, 6, 7);
}

function multiply(a, b) {
  alert(a * b);
}

JS

Any parameters after the delay are eventually passed to the timer function

  • Doesn't work in IE; must create an intermediate (anonymous) function to pass the parameters

Why not just write this?

setTimeout(multiply(6 * 7), 2000);

JS

Common Timer Errors

Many students mistakenly write () when passing the function

setTimeout(sayHello(), 2000);
setTimeout(sayHello, 2000);

setTimeout(multiply(num1 * num2), 2000);
setTimeout(multiply, 2000, num1, num2);

JS

What does it actually do if you have the ()?

  • It calls the function immediately, rather than waiting the 2000ms!

Back to our Countdown Example

countdown in console

Recall that this function prints each line immediately (in order). If we want to output each line every 1 second (1000ms), what kind of timer should we use?

Timed Countdown: An Initial Attempt

function startCountDown() {
  let i = 10;
  setInterval(function() {
    console.log(i + "...");
    i--;
  }, 1000);
  console.log("0!");
}

JS

What's wrong here? (remember we want a 10 second countdown printed to the console)

Note that we could also replace function() { ... } with () => { ... }

A Better Attempt

function startCountDown() {
  let i = 10;
  setInterval(function() {
    if (i === 0) {
      console.log("0!");
    } else {
      console.log(i + "...");
      i--;
    }
  }, 1000);
}

JS

This is closer! But there's still something wrong...

Our timer won't stop when we reach 0!

A Solution

function startCountDown() {
  let i = 10;
  let timerId = setInterval(function() {
    if (i === 0) {
      clearInterval(timerId);
      // why *don't* we need to set timerId to null in this case?
      console.log("0!");
    } else {
      console.log(i + "...");
      i--;
    }
  }, 1000);
}

JS

This is a working solution! When startCountDown is called, we assign a new interval to our timer and start a 1-second countdown at 10.

When we reach 0, we need to clear the interval from the window's tasks

Summary

When you want to call a function after a specified delay in time, use setTimeout.

When you want to call a function repeatedly every X seconds, use setInterval (though you can also use setTimeout recursively!)

For both types of timers, if you want to stop the delay/interval you'll need a variable to keep track of the timer id (returned by both functions) to pass to clearTimeout/clearInterval