Community Post

How does callback work in JavaScript

pratikpandey

JavaScript - An Introduction

JavaScript is a single threaded, event driven language. What that means is unlike traditional languages like Java/C#, JavaScript cannot spawn multiple threads to do some processing in parallel. Also, if you are performing a time consuming operation on JavaScript, since it's a single thread, it will hang your browser(since that's where JavaScript runs). Do you recall the instances where the webpage blocks/hangs? Now you know the reason for it. What else does it mean, when we say JavaScript is single threaded? Well, if you have seen traditional languages like Java, each thread has its own call stack, and since JavaScript is a single threaded language, it only has one call stack, hence as mentioned before, it can only do one thing at a time. The call stack stores the execution context of your program, and has references to objects on the heap. Till now, we talked about the single threaded side of JavaScript, but what about event driven? How does that help? And where does the event loop come in? All the above questions are answered in this post, so let's go find out.

First, I'd like to talk about what event driven means, and what makes JavaScript an event driven language. As the name suggests, it's driven by events. So you can define behaviour on the occurrence of certain events and JavaScript, provides listeners, which can listen to those events and perform certain tasks. Now that we are done covering the basics, lets jump into some hands on.

How do functions work in JavaScript -

Let's say, the following is the code we wrote -

function addNumber(a, b) {
  console.log("In call stack of addNumber");
  return a+b;
}

function multiplyNumber(a, b) {
  console.log("In call stack of multiplyNumber");
  var c = addNumber(a, b);
  return c*b;
}

console.log("in the call stack of main/anonymous function");
console.log(multiplyNumber(2,3));

Here's the link to the code. Since a stack is a FILO/LIFO DS, the output you see, is the reverse order of how it was inserted in your call stack. So your code can be thought of being inside an anonymous function, the anonymous function is placed on the thread stack. The anonymous function then calls the multiply number function, which is then placed on the thread stack. Same happens with the addNumber function. Once the addNumber completes, its stack entry is removed from the stack and now the control goes back to the current top of stack, which is multiply number. Same happens for all other functions, till the stack becomes empty, which is when your program completes. Please note that even when you have no functions, you will always have the anonymous function on the call stack.

Now let's take the following code -

function addNumber(a, b) {
  console.log("In call stack of addNumber");
  return a+b;
}

function multiplyNumber(a, b) {
  console.log("In call stack of multiplyNumber");
  var c = 0;
  setTimeout(function() {
    c= addNumber(a, b);
    console.log('Return value from addNumber - ' + c);
  }, 1000);
  return c*b;
}

console.log("in the call stack of main/anonymous function");
console.log('Final Output - ' + multiplyNumber(2,3));

Here's the link to the code. If you run the code, do you understand why it gave the output it did? If the answer is no, then there are chances you don't know about Event Loop.

Now, lets try to understand what happened. The anonymous function still calls the multiply number function, which is then placed on the thread stack. The multiply number uses a setTimeout function, which basically calls the addNumber function after 1000 milliseconds i.e 1 second. The way we called addNumber above, can also be called a callback. No big deal right, addNumber will be called after 1 second, and then using the return value, it will multiply the two values and return it and we live happily. Unfortunately/Fortunately, that's where JS differs from your traditional languages, i.e callbacks. Callbacks are JS's way to execute non blocking code, with the help of web API's provided by the browser for AJAX, timeouts etc.

Now, in the above case, when the setTimeout statement is reached, JavaScript runs that, and the Web API now get the responsibility of running that, since the WebAPI's own the setTimeout function. Once the 1 second of wait is over, the WebAPI places the callback in the callback queue. YES, callback queue, not the stack. Also, while we are talking about stack, the moment the control of setTimeout was given to the WebAPI's, Javascript thinks that the statement has executed, and it then goes ahead with the next statement. According to the above code, the next statement is -

return c*b;

Since c never got the value from addNumber function, as the function was never executed, the value of c is 0, and hence you see 0 printed as your final output.

Going back to the callback queue. Callback queue as the name suggests, is a queue which holds a list of callback functions. When will these callback functions be executed? Well, if you remember, we said that JavaScript is a single threaded language, and can process only one thing at a time i.e whatever is on the thread stack. Since the current thing in execution is the item on the stack, the callback function can't be executed. This is where event loops come in. If the stack is empty, it takes the first item on the queue and pushes it onto the stack. What happens if the stack is not empty? The event loop waits for the stack to get empty before it pushes anything onto the stack.

I don't know if you realized, but based on the above statement, if you write setTimeout(function, 1000) , 1000 is the minimum delay after which the function will be executed. If there is a lot of function calls, which means items stay on the stack for a longer time, i.e stack would not be free for a long time, you callback function will not be executed for that time. So, please take a note of this while writing AJAX calls and timeouts.

So the above was all about the internals of JavaScript and event loops. Please share if you like the post and give it a thumbs up. Also, always open for comments and questions, so drop in your questions and I will get back to you.