Asynchronous Programming: Part 2(Callback Functions)

Arpit Pundir
5 min readJun 25, 2019

--

This is second blog in Asynchronous Programming series, for better understanding of this blog firm understanding of concepts coverd in part1 (https://medium.com/@thakurarpitpundir73/asynchronous-programming-the-complete-series-c1e33b2df46f?source=friends_link&sk=13dde96dc175661762d890e0b22d72c8 ) is a prerequisite.

Till now we know what asynchronous programming is and why do we need it , we know concepts like event loop, callback queue and call stack , we also know how to make requests and get data back from a server. But we have not done anything significant with data that we got back from the server. Let’s try some possible approaches for doing so and see why they do not work.

Why do we need callback functions?

Make two js files first app.js , in this file we will be dealing with internal working of a request and second httpsRequest.js in this file we would just be calling functions of request.js to get data from the server and then use this data. First let’s make a request in request.js to server to get back a random puzzle we are using same api that we have used in previous blog.

//In httpRequest.jslet getPuzzle = (callback)=>{request.open("GET", "http://puzzle.mead.io/puzzle?wordCount=3");request.send();let request = new XMLHttpRequest();request.addEventListener("readystatechange", (e) => {if(e.target.readyState === 4 && e.target.status === 200){let data = JSON.parse(e.target.responseText);//console.log(data.puzzle)return data;}else if(request.readyState === 4){throw new Error("An error has occured");      }
}
}
});

We will call this function from our file app.js to get a puzzle from server so that we can use that puzzle as per our need.

//In app.jsconst puzzle = getPuzzle();console.log(puzzle);

Try this code output might not be what you expect i.e “undefined”. There must be something wrong with our code or in our request let’s try to debug it. Uncomment the console.log(data.puzzle) to see whether we are getting data or not and run code again.

You would see something like this. So we are getting data back from server in file httpsRequest.js, but we are not able to use it in app.js.

Reason is you are not returning data to the puzzle variable in app.js but you are returning data from anonymus function which is passed as an argument in eventlistener, to function from which this anonymus function is being called which is getData() itself. Take a look at the code again, things will make sense to you.

By now you might have already guessed the soln for this problem. We will declare a variable in getData.js , store our data in this variable and then return this variable from getData.js to app.js. Let’s try it out

let getPuzzle = ()=>{let request = new XMLHttpRequest();request.open("GET", "http://puzzle.mead.io/puzzle?wordCount=3");request.send();let data;request.addEventListener("readystatechange", (e) => {if(e.target.readyState === 4 && e.target.status === 200){data = JSON.parse(e.target.responseText);console.log(data.puzzle);}else if(request.readyState === 4){console.log("An error has occurred");}});return data;}

Surprisingly, this too do not solve our problem and we are still getting undefined even though our puzzle is stored in our data variable.

Problem this time is that addEventListener function gets triggerred when we get response back form server, but remaining code along with return statement is a part of our “now” code. As you know “now” code will execute without waiting for response from our server, so at time of execution of return statement we still have not assinged any data to to “data” variable. That’s why we see undefined on console.

Solving Problem using Callback Functions

Callback function, a function that gets passed to another function as an argument and then invoked from inside of this function.

Callback functions can solve our problem of not being able to use our request data out of our event function. How? We will pass our instructions in the form of a function, to getData() function and then we will call this function with our request returned data to use in whatever way we want in this case we will just print it. Look code below it will all make sense.

//In app.jsgetPuzzle((error,puzzle) => {if(error){console.log(error);}else{console.log(puzzle);}});

This time we have passed a callback function as argument to getPuzzle() this function can be called from getPuzzle() when we have our data.

let getPuzzle = (callback)=>{let request = new XMLHttpRequest();request.open("GET", "http://puzzle.mead.io/puzzle?wordCount=3");request.send();request.addEventListener("readystatechange", (e) => {if(e.target.readyState === 4 && e.target.status === 200){let data = JSON.parse(e.target.responseText);callback(undefined, data);//In this case we have got our data so the for error we will send undefined}else if (e.target.readyState === 4){callback("An error has occured");//In case of an error we will pass only one argument the error string ,second argument would be undefined.}});}

This time we have got it right and we are able to use our request returned data out of our event triggered function.

If this seems a little easy to you let me ask you a question, as we have discussed previously that our getData() function gets executed before we get response back from server which means all of its arguments including callback functions, variable and function itself would be removed from call stack to free memory, then how we are still able to access callback function even though it no longer exist, we will discuss this problem in next part of this blog series.

Your reviews are impotant for me to write better content, I would be glad to hear from you.

thakurarpitpundir73@gmail.com,

https://www.linkedin.com/in/arpit-pundir-091094153/

https://www.facebook.com/arpit.pundir.904

https://www.instagram.com/_thakurarpit_/

References

You Don’t know Js, https://www.udemy.com/course/modern-javascript/, mdn docs.

--

--