We know JavaScript is single threaded. And we know it uses event loop architecture. Event loop runs in a single thread & executes code. There are tons of articles out there regarding this. So without going into same thing again, I want to touch upon a follow up topic on this.
If event loop runs in a single thread, how does asynchronous events like AJAX call actually happen asynchronously? Single thread means single line of execution, so any flow will happen sequentially. So how does an AJAX call or setTimeout() call gets queued in background for asynchronous processing? Who does that & where is the background worker thread coming from if JavaScript is single threaded?
To understand this, we need to understand few high level components of JavaScript architecture.
JavaScript is single-threaded. That is right. But it actually means JavaScript engine is single threaded.
What is JavaScript engine? It is a software program which actually executes JavaScript code. It consists of a Heap & a Stack. Heap is used for memory allocation. Stack is used to track current set of instructions that is getting executed. Only one stack frame means only one function can get executed at a time. Code would be executed sequentially line by line. That’s why we call JavaScript a single threaded language.
But JavaScript is not only a JavaScript engine. Any JavaScript engine requires a host. It can’t reside on its own. It needs an environment. We call this runtime environment JavaScript runtime. Let’s take an example of famous V8 engine. It is the JavaScript engine for Google chrome & also for NodeJS. What changes between Chrome & NodeJS is the JavaScript runtime. For Chrome, JavaScript runtime is the browser. For NodeJS, it is the NodeJS server that is written mostly in C++.
Now coming back to the point, JavaScript runtime is not single threaded. It can do lot of things under the hood & multiple threads can be used there to do things. One thing you need to remember, Event Loop is not part of JavaScript Engine. It is part of JavaScript runtime. Same goes for Callback Queue.
As a host, JavaScript runtime can co-ordinate with JavaScript engine. Let’s take example of Chrome & talk about it briefly. In addition to Event Loop & Callback Queue, Chrome has something called Web API framework. The responsibility of this framework is to support asynchronous operations like AJAX API call or timeout function.
JS engine executes stack frame. If a line has WEB API call, JavaScript engine will delegate that call to Web APIs & proceed with the next line. Web API will execute the AJAX call. This happens in a different thread which is owned by JavaScript runtime. Once event is complete, Web API will push the AJAX event to Callback Queue.
The job of Event Loop is to monitor & process both stack & callback queue. It will check if stack is empty or not. If stack is processing some code, it won’t do anything. In case stack frame is empty, Event Loop will poll Callback Queue. If any completed event is there, it will push the related function back on the stack. And JS engine will execute the function from the stack.
So that is the thing. JS engine is single threaded, but JS runtime is not. As a host, JavaScript runtime supports functionalities such as Web APIs to process asynchronous events & co-ordinates with JavaScript engine to execute them once completed. That’s how JavaScript supports asynchronous execution overall.
We talked about Google Chrome browser here. We could have very well talked about NodeJS runtime. We would have just replaced Web APIs with some C++ libraries to support asynchronous callbacks. Flow would have remained same.