Lecture 10

Timers and Asynchronous Programming

Administrivia

CP2 - Lock date tomorrow at 11PM - great work so far!

HW2

  • Review and implement Part A Feedback recieved yesterday
  • Tester is out for Part B (more on next slide).
  • Remember to review provided video
  • You should have received an email about PSTutor and 2 "make up" points for HW2 - make sure to complete the survey and activities now, then submit the reflections on Friday for the 2 points.

Using Tester Part B

Screenshot of HW2 Turnin

Unzip tester-partb.zip inside of your hw2-set-<username> directory and follow the instructions on index.html

Screenshot of HW2 Tester Part B Directory Structure

Agenda

Callbacks: What are JS functions really?

Timers review

JavaScript... A Wild Ride.

Think back to your first programming language (for most of you, Java)

Unlike an object-oriented language like Java, with JS we:

  • Can listen to events like clicks
  • Can access and change HTML/CSS with the DOM
  • Don't have types (e.g. let vs. int)
  • Have a (handy?) notion of truthy/falsy
if (id("my-box")) { ... // true if exists on the page }
  • Can pass in functions as arguments???

So why is JS so different?

Java is often used to build systems.

  • Objects are great to compose together to build complex systems.
  • Systems must be reliable - a benefit of strict types, compiling, and well-defined behavior in Java.

JavaScript is used to interact and communicate.

  • It listens.
  • It responds.
  • It requests.

JS: Adding Interacitvity to Webpages

Your browsers runs JS to communicate with:

  • Users: Interactions between events and the DOM
  • btn.addEventListener("click", sayHello);
  • Servers: Requesting and recieving data
  • fetch("https://api.nasa.gov").then(...)

Whereas in Java, programs often have a well-defind specification (behavior), JS has to deal with uncertainty (weird users, unavailable servers, no internet connection, etc.)

Asynchronous Programming

The JS programs we've been writing are naturally asynchronous

We pass functions as arguments to other functions so that we can “call back later” once we know something we expect occurred.

You are a JS Developer.

Our goal is to assign tasks to events, and responsibly handle uncertainty.

Luckily, we have a handy toolset of functions:

  • addEventListener, setTimeout/setInterval, fetch, etc.)

and developer tools

  • (the Chrome debugger is your best friend!)

Remember - as a human, you already are skilled at dealing with uncertainty! Your task is just to teach JS how it needs to handle events.

We've already been writing asynchronously!

Our first example of handling "uncertain" behavior was addEventListener("click", openBox)

  • Only when the click event occurs does the function execute.

On Friday, we introduced setTimeout and setInterval.

  • Only when the delay has passed, does the function execute.

Later this week, we will introduce fetch and Promises.

  • Only after we receive a response after making a request to an API like NASA, does the function execute.

Looking More Closely at JS Functions

First-class function: Treated just like any other variable type

Can store as variables, pass as arguments to functions, return as values from functions

Defining functions as variables

function callbackFn(params) {
  ...
}

let callbackFn = function(params) {
  ...
};

let callbackFn = (params) => {
  ...
};

JS

Regardless of how we create these, we use them the same way.

let result = callbackFn(params);

JS

Passing functions as arguments

btn.addEventListener("click", callbackFn);
btn.addEventListener("click", function() {
  ...
});
btn.addEventListener("click", () => {
  ...
});

JS

setTimeout(callbackFn, 2000);
setTimeout(function() {
  ...
}, 2000);
setTimeout(() => {
  ...
}, 2000);

JS

An Example

A slight modification of the callback example from the reading

Is this a higher-order function?

function askQ(qText) {
  let answer = prompt(qText);
  if (answer === "yes") {
    console.log("You answered yes!");
  } else if (answer === "no") {
    console.log("You answered no!");
  } else {
    console.log("I have no idea what " + qText + " means.");
  }
}

JS

Demo: (starter)

Another Example

Is this a higher-order function?

function askQ(qText, yesFn, noFn, handleError) {
  let answer = prompt(qText);
  if (answer === "yes") {
    yesFn();
  } else if (answer === "no") {
    noFn();
  } else {
    handleError(answer);
  }
}

JS

function yesFn() {
  console.log("You answered yes!");
}

function noFn() {
  console.log("You answered no!");
}

function handleError(answer) {
  console.log("I have no idea what " +
              answer + " means.");
}

JS

Passing different functions

function askQ(qText, yesFn, noFn, handleError) {
  let answer = prompt(qText);
  if (answer === "yes") {
    // yesFn();
    yesFn2();
  } else if (answer === "no") {
    // noFn();
    noFn2();
  } else {
    handleError(answer);
  }
}

JS

function yesFn2() {
  id("output").textContent = "You answered yes!";
}

function noFn() {
  id("output").textContent = "You answered no!";
}

function handleError(answer) {
  console.log("I have no idea what " + answer + " means. Try again");
  processQuestion();
}

JS

Pre-Check Q2

Callbacks are a very powerful feature in event-driven programming.

Why do you think it's useful to have the ability in the JavaScript language to pass callback functions as arguments to other functions like addEventListener and setTimeout in JS?

Back to Timers

Used to delay or set intervals for executing functions

Pre-Check Q4

(function() {
  console.log("Foo 1");
  window.addEventListener("load", init);

  function init() {
    setTimeout(testFunction, 1000);
    console.log("Foo 2");
  }

  function testFunction() {
    console.log("Foo 3");
  }

  console.log("Foo 4");
})();

precheck-q4.js

Running demo

Setting a Timer

method 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 id is used as a "key" to tell the window to stop the specific timer.

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, 500);
}

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)

"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)

Questions To Think About

  1. When do you need to keep track of a timer id?
  2. Can you think of a scenario where you would want to keep track of more than one timer id?

A Typing Simulator!

Starter code: typing-simulator-starter.html

Running solution: typing-simulator.html

What other features can you think to add? A dropdown with speed? Multiple timers?

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, you'll need a variable with the timer id (returned by both functions) to pass to clearTimeout/clearInterval when you want to stop the delay/interval.