Quick facts:
async
andawait
are a modern alternative to usingPromise
objects and thethen
/catch
syntax.async
/await
allow us to write code in a more synchronous-like mannerasync
/await
utilize the more generictry
/catch
syntax to handle errors
Suppose we wanted to find all books about cheese. We could use the Google Books Api with the following URL:
https://www.googleapis.com/books/v1/volumes?q=cheese
- The host is
https://www.googleapis.com/books/v1/volumes
- The query parameter is
q=cheese
Below is a typical example of how we might fetch that data and print it using Promises and the then
and catch
methods:
function findBookAbout(searchTerm) {
const url = `https://www.googleapis.com/books/v1/volumes?q=${searchTerm}`;
fetch(url)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.log(error))
}
findBookAbout('cheese')
To generate an error response, try the url without the query parameter:
https://www.googleapis.com/books/v1/volumes
One of the issues with this current approach is that writing callback functions is a bit of a pain.
The async
/await
operators make this much cleaner. Check this out:
- First, we have to label the
findBookAbout
as anasync
function. This alllows us to use theawait
keyword inside. (See what happens when you don't include it!) - Next, we remove the
.then
method calls and insteadawait
each Promise.
async function findBookAbout(searchTerm) {
const url = `https://www.googleapis.com/books/v1/volumes?q=${searchTerm}`;
const response = await fetch(url);
const data = await response.json();
console.log(data);
}
findBookAbout('cheese')
The await
operator is used to wait for a Promise to get its fulfilled value. This allows us to write code in a synchronous-like style.
- In the example above, we wait for the Promise to be fulfilled at which point we will store the resolved value in
response
. - Only after this Promise is fulfilled do we move on to the next line of code.
- Since
response.json()
also returns a Promise, we canawait
it and store the fulfilled value indata
. - The
await
operator must be used inside a function that is marked asasync
. Note that the functionfindBookAbout
now has theasync
keyword in front.
const findBookAbout = async (searchTerm) => {
const url = `https://www.googleapis.com/books/v1/volumes?q=${searchTerm}`;
const response = await fetch(url);
const data = await response.json();
console.log(data);
}
findBookAbout('cheese')
Rule of thumb: The async
keyword goes before the function's declaration. Since arrow functions are like function expressions, technically the function declaration begins after the =
.
To handle errors using the async
/await
keywords, we turn to a more generic technique: try
and catch
. These keywords can be used to try to execute some error-prone code and catch any kind of error that may get produced.
async function findBookAbout(searchTerm) {
const url = `https://www.googleapis.com/books/v1/volumes?q=${searchTerm}`;
// wrap the error-prone code in a try {} block
try {
const response = await fetch(url);
const data = await response.json();
console.log(data);
}
// and catch any errors that are thrown
catch (error) {
console.log(error);
}
}
findBookAbout('cheese')
try
and catch
are more generic, making our code simpler overall!
We can refactor our code a bit by introducing a generic fetchFrom
method that we can reuse throughout our program.
const fetchFrom = async(url) => {
try {
const response = await fetch(url);
return await response.json();
}
catch (error) {
console.log(error);
return null;
}
}
const findBookAbout = async (searchTerm) => {
const url = `https://www.googleapis.com/books/v1/volumes?q=${searchTerm}`;
const data = await fetchFrom(url);
if (data !== null) {
// do stuff with the data!
console.log(data);
}
}
findBookAbout('cheese')
Since the data that is being returned from fetchFrom
is a Promise, we have to await
our call to fetchFrom
.