Surprise JavaScript Asynchronous
(aka Asynchronous JavaScript Surprise)
Overview
In this lab, you’ll work with asynchronous JavaScript to understand how callbacks and Promises work. You’ll implement three different buttons that demonstrate asynchronous patterns.
Learning Objectives
- Understand how
setTimeoutworks with callbacks - Work with random timing in asynchronous operations
- Use the
fetchAPI with Promises - Handle JSON responses from APIs
- Chain
.then()methods for promise handling
Getting Started
Download surprise.html and put it in your cs343 folder, in a folder called surprise.
Open it in VS Code. You’ll see three buttons already set up:
- “Call me in 5”
- “Surprise me”
- “Dog? Dog.”
Your job is to implement the three functions that make these buttons work.
Part 1: Call me in 5
Implement the callMeInFive() function:
- Display the text “Waiting…” in the display area immediately when the button is clicked.
- In the callback function, write code to change the display text to “Hi, how are you?”.
-
setTimeout()lets you delay code to run after a certain amount of time:Key Concept:
setTimeoutsetTimeout(callback, delay)executes the callback function after the specified delay in milliseconds.setTimeout(function() { // This code runs after the delay }, 5000);
Test it out! Open a preview of index.html in VS Code and click the “Call me in 5” button.
Part 2: Surprise Me
Now it’s your turn to try setTimeout() for yourself! Implement the surpriseMe() function:
- Display the text “Unaware…” in the display area immediately when the button is clicked.
- Generate a random delay between 1 and 10 seconds:
- Use the provided
getRandomNumber(min, max)helper function. - Don’t forget that
setTimeoutrequires milliseconds.
- Use the provided
- Use
setTimeout()with your random delay to schedule a callback. - In the callback function, change the display text to “Surprise!”.
Test it out! Click the “Surprise me” button and see if it works as expected.
Then, click the “Call me in 5” and then click the “Surprise me” button while you’re waiting for the first one to finish.
What happens?
Key Concept: Asynchronous Operations
Asynchronous operations (like setTimeout) allow your code to perform tasks without blocking others.
Clicking one button doesn’t block you from clicking another button. Each button’s behavior runs independently, even if they are both waiting for their respective timers to finish.
Part 3: Dog? Dog.
Asynchronous JavaScript is important for things that may take time to complete (like get data from a server/API).
The third button should go get some data from a server and do something with it. How? We’ll use the Fetch API.
Fetch API and Promises
The fetch() function is a simple way to make a network request and get data back.
However, because it may take time to get a response, fetch() doesn’t return the data directly. Instead, it returns a “Promise” that will eventually resolve to the response.
Implement the fetchDog() function:
- Display the text “Fetching…” in the display area immediately when the button is clicked.
-
Use
fetch()to make a request to the Dog API:https://dog.ceo/api/breeds/image/random- The argument to
fetch()is a string containing the URL to fetch from. - Note that
fetch()returns a Promise object, not the actual response data. - You can store the returned Promise in a variable, for example:
const responsePromise = fetch(url);
- The argument to
-
Call the
.then()method on the Promise to handle the response once it’s ready:-
The
.then()method takes a callback function with one parameter: theresponseobject, for example:responsePromise.then(function(response) { // Handle response here });
-
-
The
responseobject hastext()andjson()methods to get the response data as text or as a parsed JSON object, respectively. Let’s usejson()to get the data as an object:-
Inside the callback, add this line of code to parse the JSON:
return response.json(); -
Here’s the problem:
response.json()also returns a Promise for the parsed JSON data, so we can’t do anything with it yet.- However, if we return that Promise, then we can actually chain another
.then()!
- However, if we return that Promise, then we can actually chain another
-
-
Chain another
.then()to handle the parsed JSON data like so:const responsePromise = fetch(url); responsePromise.then(function(response) { return response.json(); }) .then(function(data) { // Here, data will be the parsed JSON object });- What’s happening here? It’s exactly how it reads:
- First,
fetch(url)makes the request and returns a Promise for the response. - Each
.then()specifies what code to run when the previous Promise finishes (“resolves”). - The first
.then()handles theresponseand returnsresponse.json(), which is another Promise for the parsed JSON data. - The second
.then()handles the parsed JSONdatacoming from whenresponse.json()resolves.
- First,
- What’s happening here? It’s exactly how it reads:
-
Inside the second
.then()callback:-
The
dataobject will be the JSON object returned by the API, for example:{ "message": "https://images.dog.ceo/breeds/hound-afghan/n02088094_1003.jpg", "status": "success" } -
Get the image URL from the object’s
messageproperty, then display the image in the display area.-
You can use
.innerHTMLto replace everything in the display area with an<img>tag, for example:display.innerHTML = `<img src='${imageUrl}' alt='Random Dog Image' />`;(Generally, we avoid using
.innerHTMLfor security reasons.)
-
-
Test it out! Click the “Dog? Dog.” button. You should see “Fetching…” and then after a moment see a random dog image.
Key Concept: Promises
Promises allow us to define callbacks to run once the response is ready, without blocking the rest of our code from running in the meantime.
Promises also allow you to chain asynchronous operations with .then(). Each .then() receives the result of the previous Promise, and can return a new Promise for the next step in the chain.
Try clicking multiple buttons in sequence to see how async operations work independently.
- For example, click “Call me in 5” multiple times, then click “Surprise me” multiple times, and click “Dog? Dog.” every so often.
- You should see how each click operates independently without blocking the others.
Challenges (Optional)
- Add error handling to the
fetchDog()function using.catch(). - Have “Call me in 5” display a countdown before showing the final message. You’ll want to use
setInterval()for this. - Add a fourth button that uses
async/awaitinstead of.then()chains.
Submission
Submit your completed surprise.html to the corresponding assignment.