Week 11 Asynchronous Programming JSON JavaScript Object Notation Lightweight data-interchange format • Simple textual representation of data ! Easy for humans to read and write ! Easy for machines to parse and generate ! Completely independent of any language 2/42 JSON JSON Syntax Rules Subset of Javascript object literal syntax… but • Property names must be in double quotes • String values must be in double quotes 3/42 JSON JSON Example Property name Value { “firstName”: “Yuksel”, “lastName”: ”Arslan”, “email”: “yuksel.arslan@ankarabilim.edu.tr”, “number of children”: 2 } 4/42 JSON JSON Example let jsonString = ‘{ “firstName”: “Yuksel”, “lastName”: ”Arslan”, “email”: “yuksel.arslan@ankarabilim.edu.tr”, “number of children”: 2 }‘ 5/42 JSON Converting JSON To String & Back to JSON Converts from json string to object: let obj = JSON.parse(jsonString); Converts from object to json string: let str = JSON.stringify(obj); 6/42 AJAX AJAX = Asynchronous JavaScript And XML. AJAX is not a programming language. AJAX just uses a combination of: ▪ A browser built-in XMLHttpRequest object (to request data from a web server) ▪ JavaScript and HTML DOM (to display or use the data) AJAX is a misleading name. AJAX applications might use XML to transport data, but it is equally common to transport data as plain text or JavaScript Object Notation(JSON) text. AJAX allows web pages to be updated asynchronously by exchanging data with a web server behind the scenes. This means that it is possible to update parts of a web page, without reloading the whole page. 7/42 Using XMLHttpRequest 3 ways of creating an XMLHttpRequest object: • IE 5: request = new ActiveXObject("Microsoft.XMLHTTP") • IE 6+: request = new ActiveXObject("Msxml2.XMLHTTP") • All others: request = new XMLHttpRequest() 8/42 XMLHttpRequest object’s properties Property Description onreadystatechange Specifies an event-handling function to be called whenever the readyState property of an object changes. readyState An integer property that reports on the status of a request. It can have any of these values: 0 = Uninitialized, 1 = Loading, 2 = Loaded, 3 = Interactive, and 4 = Completed. responseText The data returned by the server in text format. responseXML The data returned by the server in XML format. status The HTTP status code returned by the server statusText The HTTP status text returned by the server. 9/42 XMLHttpRequest object’s methods Property Description abort() Aborts the current request. getAllResponseHeaders() Returns all headers as a string getResponseHeader(param) Returns the value of param as a string. open('method', 'url', 'asynch') Specifies the HTTP method to use (Get or Post), the target URL, and whether the request should be handled asynchronously (true or false). send(data) Sends data to the target server using the specified HTTP method. setRequestHeader ('param','value') Sets a header with a parameter/value pair.. 10/42 Promises Promises are a sort of contract: •Something will happen •You can have multiple things happen. •And catch any errors. Can only go from Pending to Fulfilled or Rejected (no takebacks) Example: 'I promise to return to your table' •Pending: Waiting for my pizza •Fulfilled: Pizza has arrived!! •Rejected: Kitchen ran out of cheese. :( Promises on MDN Promises are the foundation of asynchronous programming in modern JavaScript. A promise is an object returned by an asynchronous function, which represents the current state of the operation. 11/42 Promises function description let promiseObj = new Promise(executorFn) Creates a new Promise object with the executorFn promiseObj.then(onFulfilled, onRejected) Invokes the onFulfilled (onRejected) function when the promise is fulfilled (rejected). Returns a new Promise promiseObj.catch(callback) Invokes the callback function if the promise is rejected (or an error occurs). Returns a new Promise function executorFn(resolve, reject) { // ... if (conditionMet) { resolve(); // Passed by the Promise object } else { reject(); // Passed by the Promise object } } 12/42 Promises Step 1: Make the Promise let someExamplePromise = new Promise(executorFunction) • Create a new Promise using the new Promise() constructor •Executor function: a callback function is passed into the constructor. Eventually determines the state of the promise • It is up to us to define this executor function •When created, the Promise always initially has a state of pending 13/42 Promises A closer look at the Executor Function •Function signature: include up to two parameters (both parameters are callbacks) • These parameters are commonly called resolve and reject but it does not have to be. •When called within the body of the executor function, the first parameter changes the Promise’s state from pending to resolved •The value passed in as an argument to the functions that control the state of the Promise become the value of the resolved/rejected Promises. If nothing is passed in, the value of the Promise is undefined. •When called within the body of the executor function, the second parameter changes the Promise’s state from pending to rejected function myExecFxn(res, rej) { // func implementation … // unknown time later if(/* condition */) { rej(); } else { res(); } } 14/42 Promises Step 2: Once (and if) the Promise resolves let promiseExample = new Promise(executor); promiseExample.then(someCallback) •It will take an unknown amount of time for the Promise to resolve (if it ever resolves) •Once it does (and only then), we want something else to happen •Use the .then() method to accomplish this • Pass a callback into .then() that gets called once the Promise it is chained to resolves • The value of the Promise it is chained to is passed in as the first argument to the callback in the .then() 15/42 Promises More on .then()s •A .then() wraps the return value of the callback function passed into it in a brand new Promise (this is a different Promise than the one it is chained to) •This new Promise will either resolve or reject based on the body of the callback function •The return value of the callback function passed in the .then() becomes the value of the new Promise returned by the .then() • If the callback has no return value, the value of the new Promise is undefined •Since .then()s return Promises and .then()s can be chained onto Promises, we can chain multiple .then()s together so that we can have code occur only once the previously chained Promise resolves 16/42 Promises of trivial Pizza A series A of series trivial Pizza Promise Examples Promise Examples 17/42 Promises Pizza Order with Promises function orderExecutor(resolve, reject) { // reject not usedA here series of trivial Pizza console.log('making pizza...'); Promiseour Examples setTimeout(resolve, 5000); } let orderPizza = new Promise(orderExecutor); orderPizza.then(function () { console.log('eating pizza!'); }); 18/42 Promises Pizza Order with Promises We can pass a value to resolve… function orderExecutor(resolve, reject) { console.log('making pizza...'); A seriesour of trivial Pizza setTimeout(function() { Promise Examples resolve('Here is your pizza!'); }, 5000); } let orderPizza = new Promise(orderExecutor); orderPizza.then(function (value) { console.log(value); }); That value gets passed to the function passed into “then” 19/42 Promises Pizza Order with Promises The functions passed to then can pass values to the next then callback A series of trivial Pizza eat(value) { Promise Examples function return value + ', and now it\'s gone'; } let orderPizza = new Promise(orderExecutor); orderPizza.then(eat).then(function (value) { console.log(value); }); 20/42 Promises Pizza Order with Promises You can also return other promises, which halt the execution of the next then callback until it's resolved A series of trivial Pizza function eatExecutor(resolve, reject) { Promise console.log('eating ourExamples pizza...'); setTimeout(resolve, 3000); } function eat() { return new Promise(eatExecutor); } let orderPizza = new Promise(orderExecutor); orderPizza.then(eat).then(function () { console.log('Paying the bill!'); }); 21/42 Promises Rejecting a Pizza function orderExecutor(resolve, reject) { // here MUST have both parameters defined A series of trivial Pizza setTimeout(function() { Promise Examples console.log('Pizza ordered...'); reject('Ran outta cheese. Can you believe it?'); }, 2000); } let orderPizza = new Promise(orderExecutor); orderPizza .then(function () { console.log('Woohoo, let's eat!'); }) .catch(function (value) { console.log(value); }); 22/42 WEB API An application programming interface (API) is a communication protocol that allows two pieces of software to communicate. A series of trivial Pizza A Web API is a set of predefined URLs with parameters that allow a user toPromise get Examples information from a web server. Can be used by many types of clients. 23/42 WEB API Every API has four components: 1.Where is the server that's running the API? (I.e., what's the hostname?) A series of trivial Pizza 2.Are we allowed Promise Examples to access it? 3.What content does the API give us? 4.What format should the request for content be in? What format does the response come back in? 24/42 Ajax with Fetch 1.fetch was created in 2014 and incorporated into the global window. 2.fetch takes a URL string as a parameter to request data (e.g. menu category JSON) that we can work with in our JS file. 3. A series of trivial Pizza function populateMenu() { const URL = "https://awebsite/"; Promise Examples fetch(URL + "getCategories") // returns a Promise! .then(...) .then(...) .catch(...); } We need to do something with the data that comes back from the server. 1.But we don't know how long that will take or if it even will come back correctly! 2.The fetch call returns a Promise object which will help us with this uncertainty. 25/42 Ajax with Fetch const BASE_URL = "some_base_url.com"; // you may have more than one // Step 1. Write a function to "fetch" data from a URL function makeRequest() { let url = BASE_URL + "?query0=value0"; // some requests require parameters fetch(url) .then(statusCheck) //.then(resp => resp.text()) // use this if your data comes in text //.then(resp => resp.json()) // or this if your data comes in JSON .then(processData) .catch(handleError); // define a user-friendly error-message function } // Step 2: Implement a func to process the data. You may want to break this apart // into multiple functions. function processData(responseData) { // Do something with your responseData! (build DOM, display messages, etc.) } // Step 3. Include the statusCheck function async function statusCheck(res) { if (!res.ok) { throw new Error(await res.text()); } return res; } 26/42 •When we make a call to fetch data (whether it's HTML, txt, JSON, etc) we use a function in JavaScript called fetch, which takes a URL path to fetch data from. •Here's the general template you will use for most AJAX code: async & await •async does the same thing to functions that .then() does • It wraps the return value in a Promise whose resolved value is the return value •await halts execution of the code until the Promise is resolved and then returns the resolved value of the promise 27/42 async & await Async and Await are helpful because… •Makes our code "look" synchronous again •Don't need callbacks, can just have regular functions •Can use data outside of a .then chain 28/42