Notecards

Draw a horizontal line through the middle of your big notcard.

Got picture

On the top half of the notecard write what you feel like you "got" so from doing CP 1 and CP 2 and Homework 1.

Need picture

On the bottom of the notecard, write something you feel you still need to understand, or that would help you understand this material, particularly for HW 2.

On the back of the notecard, write any questions or topics that you would particularly like to see reviewed during lab, exploration session, or optional lecture on Friday.

CSE 154

Lecture 12: AJAX, Fetch, and Promises

Agenda

HW 2 Notes

Code Step By Step problems up: Baby Sloth, Domino, Street, Resume

Answer to Friday's problem

Real world motivation for this topic!

Arrow functions

Intro to AJAX, fetch and promises

JSON exercise:

Given the JSON data at right, what expressions would produce. Assume the JSON data is stored in a object called data.

For instance, the window's title is data.window.title

  • What the debug flag is set to?
  • The image's third coordinate?
  • The number of messages?
  • The y-offset of the last message?
{
  "window": {
    "title": "Sample Widget",
    "width": 500,
    "height": 500
  },
  "image": {
      "src": "images/logo.png",
      "coords": [250, 150, 350, 400],
      "alignment": "center"
  },
  "messages": [
      {"text": "Save", "offset": [10, 20]},
      {"text": "Help", "offset": [ 0, 50]},
      {"text": "Quit", "offset": [30, 15]}
  ],
  "debug": "true"
}

Answers

Example: the window's title is :

let title = data.window.title;             // title === "Sample Widget"

JS

What the debug flag is set to?

let debug = data.debug;                    // debug === "true"

JS

The image's third coordinate?

let coord = data.image.coords[2];          // coord === 350

JS

The number of messages?

let len = data.messages.length;            // len === 3

JS

The y-offset of the last message?

let y = data.messages[len - 1].offset[1];  // y === 15

JS

Another JSON Problem

All of the class' teams group names (with student names) were typed into a .json file which we will use in an example shortly.

The structure of the file is:

{
  "teams": [
    {
      "name": "Catz",
      "students": ["Jack", "Spot", "Whitney", "Charlie"]
    },
    {
      "name": "Dawgs",
      "students": ["Mowgli", "Ruby", "Moss"]
    }
  ]
}

JSON

What could would you write to tell how many students groups there are and how many students are actually in a group?

let data = {
"teams": [
  {
    "name": "Catz",
    "students": ["Jack", "Spot", "Whitney", "Charlie"]
  },
  ...
}
let numTeams = data.teams.length;  // numTeams === 39
let count = 0;
for (let i=0; i< data.teams.length; i++) {
    count += data.teams[i].students.length;
}

JSON

How many people do you think actually signed up for a group? 108

A real world example

CSE 190z Output Comparison Tool Page

Output Comparison Tool

(View Page Source on that page or see below for an example of the code...)

CSE 190z Output Comparison Tool Page

<select id="homework">
  <option value="">(choose an assignment)</option>
  <optgroup label="Hello Buggy">
    <option value="../homework/HelloBuggy-expected-output.txt">Hello Buggy Expected Output</option>
  </optgroup>
  <optgroup label="Star Car (random seed = 28)">
    <option value="../homework/StarCar_expected_output_1.txt">Star Car Expected Output (default)</option>
    <option value="../homework/StarCar_expected_output_2.txt">Star Car Expected Output (lower case test)</option>
  </optgroup>
  ...
</select>

HTML

Is there some way we could modularize the data and read it in dynamically?

Hint: yes

But first...

Fat Arrow Functions

Fat arrow functions

Fat arrow functions are just another way of writing an anonymous function.

//define an anonymous function and assign it to mult
let mult = function(a, b) { return a * b };
let result = mult(4, 5); // result === 20

// create an anonymous function mult2 using the fat arrow notation
let mult2 = (a, b) =>  a * b;
let result2 = mult2(4, 5); // result2 === 20  

JS

You do not need to use fat arrow functions in your work but ...

  • they were in your readings
  • they appear to be gaining a lot of favor in code
  • there are some benefits to them vis-a-vis this

Fat arrow function syntax

Some sample basic syntax (from MDN)

(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// equivalent to: => { return expression; }

// Parentheses are optional when there's only one parameter name:
(singleParam) => { statements }
singleParam => { statements }

// The parameter list for a function with no parameters should be written with a pair of parentheses.
() => { statements }

JS (template)

let max = (a, b) => a > b ? a : b;
// Array filtering
let arr = [1, 2, -1, 0, 3, 4, 6, 20];
let even = arr.filter(v => v % 2 == 0);
// [2, 0, 4, 6, 20]

JS (examples)

Fat arrow functions in CSE 154

  • This information on the "fat arrow" notation was mostly "FYI" because you are going to run in to them in documentation.
  • You may continue to use anonymous functions as taught previously (function() { }) or use fat arrow functions as you feel comfortable with them. You do NOT have to use fat arrow functions at all.
  • As always, we would prefer you be consistent in your usage of either regular anonymous functions or fat arrow functions as that is good Code Quality
  • Remember to only use anonymous functions (in general) when you have a small number of statements that won't need to be reused or duplicated anywhere.

AJAX

web application:
a dynamic web site that feels like a desktop application
AJAX:
a specific style of using JS to call out to the server for more information
AJAX with the Fetch API:
A newer, easier way to accomplish AJAX calls
Promise:
a JS object that is useful for dealing with uncertainty in your program

Web Applications

All of the pages that we've made up until now have content, style, and behavior.

Web applications are webpages that pull in additional data and information as the user progresses through them, making it feel similar to a desktop application.

Some motivations for making web pages into web applications:

  • Better user experience
  • Less data sent across the wire
  • Leads to good software architecture:
    • Client handles display, server serves up data

Synchronous requests:

synchronous request diagram

Why synchronized requests are problematic

Your code waits for the request to completely finish before proceeding. Might be easier for you to program, but the user's entire browser LOCKS UP until the download is completed, which is a terrible user experience (especially if the page is very large or slow to transfer)

Asynchronous requests:

asynchronous request diagram

Watching requests

Use the inspector, watch the network tab to see the requests that go out.

Watching network requests

AJAX the "old way" (XML over HTTP)

Using Javascript to pull in more content from the server without navigating the page to a new url

Although we are showing you this, it is for context only, we will not be using the "XML over HTTP" method of AJAX calls.

let xhr = new XMLHttpRequest();
xhr.open(method, url, [async/sync]);
xhr.onload = function() { /* handle success */ };
xhr.onerror = function() { /* handle failure */ };
xhr.send(); 

JS (template)

let xhr = new XMLHttpRequest();
xhr.open("GET", "data.txt");
xhr.onload = function() { alert(this.responseText); };
xhr.onerror = function() { alert("ERROR!"); };
xhr.send();

JS (example)

AJAX
Asynchronous JavaScript and XML

The XMLHttpRequest object can be used synchronously or asynchronously.

So this functionality could be called S/Ajax or A/Sjax. But Ajax has a nice ring to it.

It's better to use async so that the page doesn't block waiting for the page to come back. We have no use cases in this class for using Ajax synchronously.

AJAX
Asynchronous JavaScript and XML

the XMLHttpRequest object can be used to fetch anything that you can fetch with your browser.

This includes XML (like in the name), but also JSON, HTML, plain text, media files.

So it could be called Ajaj or Ajah or Ajat. But Ajax has a nice ring to it.

AJAX with the Fetch API

The Fetch API was created in 2014 and incorporated into the window DOM object.

(function(){
  ...
  function doWebRequest() {
    let url = ..... // put url string here
    fetch(url);
  }

JS (template)

Example: AJAX with the Fetch API

You can use a relative path name to fetch a file file that is retreived from the same directory as the .js file.

You can also pass absolute path to a file (i.e. a full URL) in the argument to fetch

function loadTeams() {
  const url = "teams.txt";
  fetch(url);
  ...
}

JS (example)

Now that we've done a fetch, we need to do something with the data that comes back from the server.

But we don't know how long that will take or if it even will come back correctly!

The fetch call returns a Promise object which will help us with this uncertainty.

Promises

Real world promises

Promises have three states:

  • Pending
  • Fulfilled
  • Rejected

Example: “I promise to post CP 3”
Pending: Not yet posted
Fulfilled: CP 3 posted
Rejected: Wrong homework posted, or not posted in time

JavaScript Promises

promise
A JS object that executes some code that has an uncertain outcome

Promises have three states:

  • Pending
  • Fulfilled
  • Rejected
let promise = new Promise(function(resolve, reject) {
  // do something uncertain (like make an ajax call)

  if (success) {
    resolve();     // Fulfilled
  } else {
    reject();      // Rejected
  }
});

JS (template)

A Promise is returned from a fetch call

We will be using promises when we fetch information from a server, which is an uncertain task

We give you "boilerplate" starting code because you will use this frequently

Ajax fetch Code Skeleton

// based on: https://developers.google.com/web/updates/2015/03/introduction-to-fetch
function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response.text();
  } else {
    return response.text().then(Promise.reject.bind(Promise));
  }
}

function callAjax() {
  let url = ..... // put url string here
  fetch(url)
   .then(checkStatus)
   .then(function(responseText) {
      //success: do something with the responseText
    })
   .catch(function(error) {
     //error: do something with error
   });
}

JS (template)

Ajax fetch Code Skeleton (better variation)

function checkStatus(response) {    // boiler plate code given out
  ...
}

function callAjax() {
  let url = ..... // put url string here
  fetch(url)
       .then(checkStatus)
       .then(handleResponse)
       .catch(handleError);
}

function handleResponse(responseText){
  //success: do something with the responseText
}

function handleError(error){
  //error: do something with error
}

JS (template)

Randomizer example

A real world example for randomizing groups of people!

(Click on the image and View Page Source on that page to see the code...)

Cross origin security concerns

Generally speaking, you can only send Ajax requests to the server that your page came from.

This is to prevent rogue JavaScript from being able to call out to any server and pull in whatever content it wants to.

Mostly, you can't do Ajax request when your URL starts with file:/// (i.e. you've double clicked on your .html file to bring it into the browser.

ajax security image

Solutions: request your website from a server

A few possiblities here

  • Install the Web Server for Chrome extension, and serve your pages from http://127.0.0.1:8887/
  • Install and run MAMP for Macs or WAMP for Windows, and serve your pages from http://localhost:8888/ (for Macs) or http://localhost/ for PCs
  • Use FileZilla to upload your files to your Student Web Server Space to serve your files from there (https://students.washington.edu/yournetid/)
Chrome Server MAMP Server

Summary: Why are promises/fetch useful?

The help deal with uncertainty in your code. You never know exactly what will happen when you make an Ajax call, so wrapping the call in a Promise is a nice way to deal with the uncertainty.

The paradigm is nice because you write the anonymous function that defines the promise, so you are the one who writes the code that determines whether the promise was 'fulfilled' or 'rejected'.

You also define what happens after the Promise fulfills with the then function, and what happens when it rejects in the catch function.

Summary: Using AJAX

  • using JS to download data (or other stuff) from the server in the background
  • not a programming language; its a particular way of using JavaScript
  • allows dynamically updating a page without making the user wait
  • avoids the "click-wait-refresh" pattern
  • JSON is now more common than XML, but they are both just ways to store data
  • Using the Fetch API for AJAX can produce "cleaner" and more maintainable code
  • examples: UW's CSE 14x Diff Tool, Practice-It; Amazon product pages, most auto-complete search features
ajax diagram