-
Javascript can only execute one thing at a time, if there is a process that is time costly like communicating with a database, we have ways to handle these processes asynchronously
-
callback pattern - if we want to ensure a particular sequence of execution, traditionally one way we do this is via callbacks
-
since functions can be passed around as arguments, callbacks involve taking another funciton as an argument so that the callback is only executed after the asynchronous task/function completes
-
this works fine for simple callbacks, but if there is a series of events you need to happen you encounter callback hell , aka Pyramid of Doom aka spaghetti code
-
an example of an async function that takes in a callback and a time delay as arguments
-
after the time delay elapses, the callback function is scheduled to be executed
Promise
- native to ES6, Promises were developed to help us deal with callback hell, makes code more readable and easier to debug
// basic structure for making a new promise via Promise class
exampleFunction = () => {
return new Promise((resolve, reject) => {
}
}
// importantly what's inside the block of the promise can be an async function which is dope
new Promise((resolve, reject) => {
// do something asynchronously
if (/* things are successful */) {
resolve("It worked!") // execute .then()
} else {
reject(Error("It broke!")) // execute .catch()
}
})
.then((result) => {
// result is the argument from the resolve above
// process data, add elements to the DOM, etc...
console.log(result)
})
.catch((err) => {
// err is the argument from the reject above
// show user an error message, retry network request, etc...
console.log(err)
})
Terminology
-
Pending - he promise has not been responded to yet
-
Settled - the promise has received some response, it is either:
-
fulfilled - things went well, triggers the function in .then ( )
-
rejected - things are not dope, triggers the funciton in .catch( )
Chaining
-
one of the most powerful aspects of Promises is chaining, the ability to chain multiple .thens to guarentee execution in a predictable order
-
what’s super dope is that if any of the .thens results in an error, it will skip any other .thens and go straight to the .catch
- in the wild you may not be generating raw Promises often, our interaction with Promises will usually be on new technology built with it such as the Fetch API
- will become especially useful when we move to React
- evolution from AJAX, easier for us to interact with, can also chain more easily versus .done() callback pattern in ajax
Promise and Reponse
-
Fetch API is used to fetch resources from a server and returns a promise
-
Once promise is fulfilled we are given a Response object
-
useful attributes and methods such as status, ok boolean, json() method
-
if the server response was erroneous it doesn’t automatically trigger the catch, must check the response.ok() boolean and throw an error if not okay
// typical flow of a fetch
fetch('http://localhost:4567/books.json')
.then(response => {
if (response.ok) {
return response;
} else { // if response was not okay, throw an error to trigger .catch
let errorMessage = `${response.status} (${response.statusText})`,
error = new Error(errorMessage);
throw(error);
}
})
.then(response => response.json())
.then(body => {
console.log(body);
})
.catch(error => console.error(`Error in fetch: ${error.message}`));
Post
- fetch defaults to GET if no verb given
- if back end is expecting in JSON format, make sure to JSONify before sending it
// typical post FETCH
let data = {
book: {
name: 'book from fetch'
}
};
let jsonStringData = JSON.stringify(data);
fetch('http://localhost:4567/books.json', {
method: 'post',
body: jsonStringData
}).then(response => {
if (response.ok) {
return response;
} else {
let errorMessage = `${response.status} (${response.statusText})`,
error = new Error(errorMessage);
throw(error);
}
})
.then(response => response.json())
.then(body => {
console.log(body);
})
.catch(error => console.error(`Error in fetch: ${error.message}`));
Fetch exercise solution
fetch('http://localhost:4567/books.json')
.then(response => {
if (response.ok) {
return response;
} else {
let errorMessage = `${response.status} (${response.statusText})`,
error = new Error(errorMessage);
throw(error);
}
})
.then(response => response.json())
.then(body => {
return(body.books)
}).then(books => {
books.forEach(book => {
$("#books").append(`<li>book: ${book.name} </li>`);
})
})
.catch(error => console.error(`Error in fetch: ${error.message}`));