For those who just got in touch with JavaScript might be confused when hearing people say that JavaScript is a single threaded and non-blocking programming language. You might be thinking how could one be single threaded but non-blocking?
Single Threaded
JavaScript is known to be single threaded because of its property of having only one call stack, which some other programming languages have multiple. JavaScript functions are executed on the call stack, by LIFO (Last In First Out). For example we have a piece of code like this:
const foo = () => {
const bar = () => {
console.trace();
}
bar();
}
foo();
And the call stack will have foo to enter into call stack, then bar.
After bar() is done, it will be popped off from the call stack, followed by foo(). You will see an anonymous function underneath when printing out the stack trace, and that is the global execution context of main thread.
This seems to be logical as JavaScript is a single threaded language and there is only a single flow to execute all these functions. However, in the case that we are having some unpredictable or heavy tasks in the flow (for example making an API call), we do not want them to block the execution of the remaining codes (else users might be staring at a frozen screen). This is where the asynchronous JavaScript comes in.
Non-Blocking
Other than JavaScript Engine, we also have Web APIs, Callback Queue and Event Loop to form JavaScript runtime in the browser. Let's say we have a piece of code here:
console.log("1")
setTimeout(() => console.log("2"), 5000)
console.log("3")
"setTimeout" is a Web API function that will execute a callback function after a certain amount of time (in milliseconds, in this case is 5000 milliseconds). When you execute this script, you will see that "1" and "3" are printed out instantly, and "2" is printed out around 5 seconds later.
This is what happened behind the scene:
The first console log is put into the stack, and popped off after printed out "1" in the console. When setTimeout function is put into the stack, the callback function is set to await by this Web API function. The setTimeout function is then popped off the stack and the third console log enters. After finished executing, the third console log and the current global execution context are popped off from stack.
When the callback function in setTimeout finished awaiting, it will be entering to Callback Queue (or event queue) and waiting to be executed. Event loop facilitates and checks if the call stack is empty. If it is empty, new global execution context is created and this call back function (console log out "2") will then be put into the stack, executed and popped off.
Just to add on, even if you are setting setTimeout to delay by 0 second, "2" will still be the last one to be printed out because as long as Web API is called, it will be put into Callback queue and be placed onto stack only when the stack is empty.
I hope this gives you an idea of why JavaScript can be single threaded and non-blocking at the same time. Thought of writing this as I just recently shared this with the new joiner to our company.
Oh btw, if you still need a video explanation, here is a good resource:
What the heck is the event loop anyway? | Philip Roberts | JSConf EU
Do follow me for more future articles on web design, programming and self-improvement π
Top comments (1)
thanks for this explanation