From Callbacks to Async Await
I built the same program 4 different ways. I started with callbacks, moved on to Promises, used generators, and finished up with async/await.
The program:
-
Makes a request to Github’s users endpoint
-
Pulls back my Github profile
-
Logs the response
Here’s what I came up with.
Callbacks
I struggled to make an HTTP request using callbacks. I’ve mostly used Promises to write asynchronous JavaScript. I generally use axios or fetch in my applications, which are both Promise-based.
I ended up having to turn to XMLHTTPRequest for this version of the application, which I’ve never used before!
const makeHTTPRequest = (url, methodType, callback) => { const xhr = new XMLHttpRequest(); xhr.open(methodType, url, true); xhr.onreadystatechange = () => { if (xhr.readyState === 4 && xhr.status === 200) { callback(xhr.responseText); } }; xhr.send(); }; const getLogin = (response) => { console.log(JSON.parse(response)); }; const url = "https://api.github.com/users/maecapozzi"; makeHTTPRequest(url, "GET", getLogin);
I’ll walk you through what this code does:
-
I define a function called
makeHTTPRequest
. It’s designed to actually make the request to Github. -
I pass three methods to
makeHTTPRequest
,url
,methodType
, andcallback
.url
is the endpoint I want to hit.methodType
is the HTTP method I want to use. Andcallback
is the function I want to call when I actually get a response back from Github. -
I define a function called
getLogin
and pass it response as an argument. The function takes the response I receive from Github, and parses it to JSON. Then, it logs the parsed response. -
I pass
getLogin
intomakeHTTPRequest
as callback. That meansgetLogin
will take the response from Github has it’s argument.
Promises
After achieving my goals with callbacks, I attempted with promises. This felt straightforward, since I’ve done it many times before.
const makeHTTPRequest = (username) => { const url = "https://api.github.com/users/" + username; fetch(url) .then((response) => response.json()) .then((response) => console.log(response)); }; makeHTTPRequest("maecapozzi");
-
I defined a function called
makeHTTPRequest
and passed it ausername
. -
I used
fetch
to make a request to Github. -
I use
.then()
to wait for the request to Github to complete, and then convert the response to JSON. -
I log the response
Generators
This was my first foray into generators. The syntax and concept were totally foreign to me upon approaching this challenge.
function* getUser(username) { const uri = "https://api.github.com/users/" + username; const response = yield fetch(uri); const parsedResponse = yield response.json(); console.log(parsedResponse); } getUser("maecapozzi");
-
I define
getUser
and say that it’s a generator by using the*
syntax. I pass in username as an argument. -
I create a variable called
response
and set it equal to response I receive from Github after making an HTTP request usingfetch
. The important piece of line 3 is that I use the keywordyield
.yield
is telling my program that I do want to set response equal to the response I get back from Github, but only after the request is completed. -
I follow the same pattern again when I set
parsedResponse
equal toresponse.json(
). I have to wait for the Promise to resolve before I can set my variable. If I don’t useyield
, when I try to logparsedResponse
, I get:Promise {<pending>}
back.
Async/Await
Finally, I wrote the application once more using ES7 async/await. Since I did this after building the same application with generators, it became really obvious how async/await is built on top of generators.
const getUser = async (username) => { const uri = "https://api.github.com/users/" + username; const response = await fetch(uri); const parsedResponse = await response.json(); console.log(parsedResponse); }; getUser("maecapozzi");
-
I define an async function called getUser that takes username as an argument.
-
I created a variable called
response
and set it equal to the response I receive from Github after making a request to the/users/:id
endpoint. The key is that I use theawait
keyword to tell my program to wait for the request to resolve itself before setting response equal to the response I get back. -
I use the same pattern again on line 4.
-
Then I log the parsed response.
Takeaways
This was a worthy endeavor for a few reasons. First of all, I hadn’t used callbacks much, so I didn’t really know how big of a deal Promises were. I also had been taking fetch and axios for granted, since they made making HTTP requests so much more straightforward.
I also had never used generators or async/await. Although I found async/await much easier to use than generators, it was helpful to see how async/await was built on top of generators. It was also fun to get my hands dirty with some ES7 syntax.