.Fetch() and Her Daughters (Async and Await)
An overview of .fetch() and the special methods you’ll frequently see her with
In 2015, Javascript introduced the Fetch API, an interface for client-server communication. Before this, we used XMLHttpRequest, or XHR, which uses callback functions to handle server requests. Because of Javascript’s asynchronous nature, the use of deeply nested callbacks can be difficult to manage. This issue became known as callback hell. The Fetch API came along with a solution to callback hell: the implementation of promises, and it has become widely adopted by browsers today.
The .fetch() method is what we use in our Javascript code to request JSON or XML data from an API. One argument is required, although it accepts two: a URL and options. The URL is the URL address to which the request is being made. Used without the options parameter, the .fetch() will simply request some data to view. Used with the options parameter, it can be utilized to create, delete or update data in a server.
Here’s the thing about client-server communication: it takes some time. We need to send our fetch request out, allow the server generate a response, and let the server to send that response back. Only .then do we receive and do something with that response. This process takes longer than the rest of our Javascript code will take to run. Because of this, .fetch() is an asynchronous function that returns a promise. What the heck does that mean?
It means that when our .fetch() function runs it will immediately return a theoretical representation of the server’s response (i.e. a promise). After that, the following lines of code will continue to run while we wait for our server’s response (i.e. the code runs asynchronously). We can then call some special methods on our promises, which will wait until we receive the data from our fetch request. Then, these special methods will inform our code about what to do with that data.
.then() is one of those special methods, and we use it when the promise is resolved properly — when we successfully get the data we were looking for. We chain .then() to the end of our fetch call, and it takes in a function as its argument. We can then grab the response from our fetch request and perform some kind of function on it. It kind of looks like this:
Keep in mind that, at this point, our response in the above example is not something we can render to our app’s front end; it’s still just a promise object. Most of the time we need to turn that data into something we can manipulate for the client side. We’ll use the .json() method which parses a JSON object and turns it into a regular, ol’ Javascript object. The .json() method is an integral part of our server-response cycle, and it also returns a promise. Because of that, we’ll chain another .then() and then we can do whatever we want with that data. Our syntax now looks a little more like this:
The only trouble I’ve run into with using .then() is when I’m chaining fetch requests. What if I want to use the data that I literally just got back to make another fetch request? What if I’m creating a new User and then I need to create a new Pizza that belongs to my new User? We could put another fetch request inside of our .then() statement, but that gets messy when we start chaining fetch requests inside of fetch requests inside of…
Enter async/await. Using the async/await syntax can essentially capture the same functionality as .then() but without the chaining. Javascript people call it syntactic sugar, and it gives the illusion of synchronous behavior despite its asynchronous nature. This makes it easier to read, write and debug when utilizing fetch requests that rely on other fetch requests. Here’s what our syntax looks like:
To use async/await, first we notate our function with the async keyword. Inside, we create a variable for our fetch request that we mark with the await keyword. This will cause our function to wait until our fetch request completes before moving on. Our response variable here is the same as the response from our .then() example — first its a promise and then a response object once successfully we receive our data. Again, we’ll need to de-JSON-ify our response object by using the counter-intuitive-ly named .json() method:
What if our server doesn’t successfully get us back what we were looking for? We need to handle our errors. For this, .catch() is our guy. Basically, we can chain .catch() to the end of our fetch calls, and if that fetch turns up an error, we can read it in our catch. Here’s what the syntax could look like if we’re using .catch() with both .then() and async/await:
Ultimately, these both capture the exact same functionality, and neither is going to work better than the other. It’s up to you to decide which you find easier to read, write and maintain. Like I said earlier, I prefer to use the async/await keywords for long chains of fetch calls. Otherwise, I find .then() easier to read.
Finally, there’s also .finally(). This method can be chained at the end of your fetch request if there’s a specific task you want done whether the fetch request is successful or returns an error. The syntax is the same as .then() and .catch(). Say you want to thank your reader for sticking around… see y’all next time!
Sources:
https://en.wikipedia.org/wiki/XMLHttpRequest
https://www.geeksforgeeks.org/javascript-fetch-method/
https://developer.mozilla.org/en-US/docs/Web/API/Response/json