GDI Logo

Intermediate JavaScript

Class 3

Agenda

  • Review Quiz
  • Asynchronous JS
  • API's
  • fetch()

Review Quiz

What is wrong with the following function?


function factorial(n) => {
  if (n===1) {
    return 1;
  }
  return n * factorial(n-1);
}
            

// It's trying to combine 2 different ways of defining a function
// Could go with function declaration...
function factorial(n) {
  if (n===1) {
    return 1;
  }
  return n * factorial(n-1);
}
            

// ...or arrow function
const factorial = n => {
  if (n===1) {
    return 1;
  }
  return n * factorial(n-1);
}
            

How would you access the 2nd item in the object's array?


const superman = {
  name: "Kal-El",
  alter_ego: "Clark Kent",
  origin: "Krypton",
  powers: ["strength","x-ray vision","indestructibility","ice breath","eye beam"]
}  
          

superman.powers[1]; // x-ray vision
          

I can't see the <p> element I added to the DOM. Here's my "script.js" file. Why isn't it working?😭


const container = document.querySelector(".container");
const p = document.createElement("p");
p.innerHTML = "Hello World!";
            

// Need to attach/append the newly create element to a DOM element
container.append(p);
            

I made the change - my JavaScript is correct, but I still can't see the <p> element on the website. Here's my "index.html" file. Why isn't it working?😭


<html>
  <head>
    <title>Cool Site</title>
  </head>
  <body>
    <div class="container"></div>
  </body>
</html>
            

<html>
  <head>
    <title>Cool Site</title>
    <!--Forgot to load the JavaScript file!-->
    <script src="script.js"></script>
  </head>
  <body>
    <div class="container"></div>
  </body>
</html>
            

Synchronous JavaScript

JavaScript executes each line of code from top to bottom


const name = "Bob";
const age = 42;
console.log(name); // Bob
console.log(age); // 42

This is a common and expected behavior of code execution

Asynchronous Real Life

  • Your left in charge of the house and your mom has left you a TO-DO list:
    1. Schedule vet appt.
    2. Take out garbage
    3. Wash the dishes
  • You're very particular and want to do everything in order (like JS!)
  • When you call the vet, you're put on hold...
  • You're not going to just wait around! While on hold, you take out the garbage and wash the dishes
  • Eventually, the vet comes back and you schedule the appt.

Asynchronous JavaScript

There are instances when code will get executed, but NOT resolve immediately, such as requesting information from an API server


const URL = "https://randomuser.me/api";
let data;
fetch(URL) // Requesting JSON from API (like $.ajax)
  .then(response=>response.json())
  .then(json=>{
    data=json;
  })
console.log(data); // undefined

During code execution, the fetch() call sends a request to a URL, but that could take a long time (~6ms)! JavaScript is not going to wait - it will move onto the console.log() and let callbacks handle the response

Let's Develop It! (Instructor only)


const URL = "https://randomuser.me/api";
let data;
fetch(URL) // Requesting JSON from API (like $.ajax)
  .then(response=>response.json())
  .then(json=>{
    data=json;
  })
console.log(data); // undefined
          
  • Run the previous slides' code in the browser
  • console.log(data) again after a few seconds
  • What's happening?

API's

API stands for Application Program Interface

  • API's allow computers to communicate with other computers, usually through JSON
  • For Example, the Random User API returns JSON of a typical user as an object with random properties like name, address, passwords, and phone numbers - it's also a great introductory API!


Example JSON from Random User API


{"results":[{"gender":"female","name":{"title":"ms","first":"carolyn","last":"brooks"},"location":{"street":"5508 king street","city":"wakefield","state":"warwickshire","postcode":"M0 5UX","coordinates":{"latitude":"14.0309","longitude":"165.8724"},"timezone":{"offset":"+8:00","description":"Beijing, Perth, Singapore, Hong Kong"}},"email":"carolyn.brooks@example.com","login":{"uuid":"31cd84ee-8a01-4254-b322-675ef00de0fa","username":"bluegorilla497","password":"birthday","salt":"Nbhjusmn","md5":"6bc053eccfdc3078acab5d96b5278f0f","sha1":"371147ed185f134a65e0f201b0f82b5e55ff2223","sha256":"60fc47a547217783428ffc170709adc8bad0efa5404fff41282c57d9b37c33ba"},"dob":{"date":"1962-08-29T20:41:30Z","age":56},"registered":{"date":"2016-12-08T04:51:11Z","age":2},"phone":"028 3843 5424","cell":"0770-555-954","id":{"name":"NINO","value":"LH 29 72 52 O"},"picture":{"large":"https://randomuser.me/api/portraits/women/95.jpg","medium":"https://randomuser.me/api/portraits/med/women/95.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/95.jpg"},"nat":"GB"}],"info":{"seed":"ed31d9a21fc2e60e","results":1,"page":1,"version":"1.2"}}
            

A cautionary tale...

  • Typically, API servers are set up to protect themselves from excessive requests from a single source, or IP address
  • When too many requests come in, the server will often blacklist the IP address for 15 minutes or more
  • This is why the last activity was just for the instructor!
  • In the later activities, if your wifi's IP address is blacklisted - just use the backup data provided as a substitute

Let's Develop It!

  • In your browser, go to the url - https://randomuser.me/api
  • Open the browser's console and store the JSON (copy and paste it) in a variable "json"
  • How would you access the following properties:
    • cell number?
    • username?
    • API version?


Backup JSON from Random User API - just in case!


  {"results":[{"gender":"female","name":{"title":"ms","first":"carolyn","last":"brooks"},"location":{"street":"5508 king street","city":"wakefield","state":"warwickshire","postcode":"M0 5UX","coordinates":{"latitude":"14.0309","longitude":"165.8724"},"timezone":{"offset":"+8:00","description":"Beijing, Perth, Singapore, Hong Kong"}},"email":"carolyn.brooks@example.com","login":{"uuid":"31cd84ee-8a01-4254-b322-675ef00de0fa","username":"bluegorilla497","password":"birthday","salt":"Nbhjusmn","md5":"6bc053eccfdc3078acab5d96b5278f0f","sha1":"371147ed185f134a65e0f201b0f82b5e55ff2223","sha256":"60fc47a547217783428ffc170709adc8bad0efa5404fff41282c57d9b37c33ba"},"dob":{"date":"1962-08-29T20:41:30Z","age":56},"registered":{"date":"2016-12-08T04:51:11Z","age":2},"phone":"028 3843 5424","cell":"0770-555-954","id":{"name":"NINO","value":"LH 29 72 52 O"},"picture":{"large":"https://randomuser.me/api/portraits/women/95.jpg","medium":"https://randomuser.me/api/portraits/med/women/95.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/95.jpg"},"nat":"GB"}],"info":{"seed":"ed31d9a21fc2e60e","results":1,"page":1,"version":"1.2"}}
              

Let's Develop It! - Answers


json.results[0].cell;
json.results[0].login.username;
json.info.version;

Callbacks

A callback is a function that is passed into another function as an argument to be called later

  • Usually, we define functions and call them directly
  • 
    const add = (a,b) => a + b;
    add(1,3); // 4
    
  • However, functions are variables, too, and can be passed as arguments!
  • 
    const numbers = [1,2,3];
    combineArray(numbers, add); // We'll define "combineArray" in a sec!
                  

NOTE: when passing a callback, do NOT use parenthesis, which would immediately invoke the function

Callbacks

  • The function being passed as an argument is known as a callback
  • 
    const add = (a,b) => a + b;
    
    /**
     * Combines each element of the given array
     * using the given combiningFunction.
     */
    const combineArray = (arr, combiningFunction) => {
      let total = arr[0];
      for(let i = 1; i < arr.length; i++){
        total = combiningFunction(total, arr[i]); // callback called here
      }
      return total;
    }
    
    const numbers = [1,2,3];
    combineArray(numbers, add); // 6
    

Callbacks

  • The function recieving the callback is known as a higher-order function
  • Higher-order functions separate logic and allow developers to determine how they want to handle code execution
  • 
    const stringify = (a,b) => String(a) + String(b);
    
    /**
     * Combines each element of the given array
     * using the given combiningFunction.
     */
    const combineArray = (arr, combiningFunction) => {
      let total = arr[0];
      for(let i = 1; i < arr.length; i++){
        total = combiningFunction(total, arr[i]); // callback called here
      }
      return total;
    }
    
    const numbers = [1,2,3];
    combineArray(numbers, stringify); // "123"
    

BREAK

Using fetch()

fetch() is a default function in the browser that can make HTTP requests

  • fetch() takes a URL string, which it uses to make the request
  • 
    const URL = "https://randomuser.me/api";
    fetch(URL);
              
  • A Promise object is returned, which has a .then() method
  • .then() takes a callback and passes a single argument to the callback!

const URL = "https://randomuser.me/api";
const handleResponse = response => {
  // do something with response
}
fetch(URL).then(handleResponse);
            

Let's Develop It!


const URL = "https://randomuser.me/api";
const handleResponse = response =>{
  console.log(response);
}
fetch(URL).then(handleResponse);
            

Run the above code in the browser

  1. What is passed into the "handleResponse" callback?
  2. Explore the Response object and find the .json() method under __proto__
  3. Call the .json() method within the console.log() - what does it return?
  4. Have the "handleResponse" return response.json()
  5. Attach another .then() to the previous .then() and provide the function "handleJSON" as its argument
  6. Define the "handleJSON" function - console.log() the data passed into it from the second .then()

Let's Develop It! - Result


const URL = "https://randomuser.me/api";
const handleResponse = response => response.json();
const handleJSON = json => console.log(json);
fetch(URL).then(handleResponse).then(handleJSON);
            

The "handleJSON" function should console.log() the same object you can see when going directly to https://randomuser.me/api in the browser

Remember from earlier...


const URL = "https://randomuser.me/api";
let data;
fetch(URL)
  .then(response=>response.json())
  .then(json=>{
    data = json; // setting data!
  })
console.log(data); // undefined...wait, what!?
                        
  • The JSON from the response CANNOT be accessed synchronously
  • The JSON only exists within the "handleJSON" callback - so it's the only place we can actually make use of it!

Let's Develop It!

In the "mainProject" folder, go into "class_3", and edit the "script.js" file

  • Follow the instructions for making the "addQuestions" function and modifying some previous code
  • Be sure to explore what data the API sends back and get a good grasp of the flow of information

Take Home Assignment

Additional Resources