One of the great features of JavaScript is that it is a single-threaded-based language. Single thread means that only one task can be processed at the same time. However, if you consider the environment in which JavaScript is actually used, you can see that a lot of work is being processed at the same time.
For example, a web browser processes mouse input while displaying an animation effect, on the other hand, a Node.js based web server handles multiple HTTP requests simultaneously. How could this be possible with a single thread? In other words, “How does JavaScript support Concurrency?”
The concept that emerges this time is the Event Loop. When introducing Node.js, you’ve probably seen phrases like ” Non-Blocking I/O support in an event loop-based asynchronous approach… “. That said, JavaScript supports asynchronous I/O and concurrency by using event loops.
Node.js with this event loop could be hard for someone familiar with using other languages in a synchronous way such as Java. Not only that, even those who have been using the service for a long time and are familiar with programming how to use it are not know in detail how the event loop actually works.
Even if you search through JavaScript-related books, it is surprisingly difficult to find a description of the event loop. The reason is probably that ECMAScript specification doesn’t really have anything about event loops.
To be more specific, you can say “ECMAScript doesn’t mention concurrency or asynchronous” ; technically, it has changed slightly since ES6, but I’ll explain more later. In fact, JavaScript engines like V8 use a single Call Stack, and each time a request comes in, the request is sequentially placed on the call stack and processed.
How are asynchronous requests made and what handles concurrency? The answer is a JavaScript engine runtime environment: browser or Node.js is responsible for asynchronous work.
Check a simple diagram of the browser environment below.
As you see, functions such as setTimeout() and XMLHttpRequest() are actually used for asynchronous calls are defined separately in the Web API area, not in the JavaScript engine. Furthermore, Event loops and Task queues are also implemented outside of the JavaScript engine. Next is the Node.js environment.
In the diagram above, Node.js structure is similar to the browser’s environment. As well known, Node.js supports asynchronous I/O using libuv library and this libuv provides an Event loop.
The JavaScript engine calls the API of Node.js for asynchronous operation, then the callback is scheduled and executed through the event loop of libuv.
In brief, “JavaScript is a single thread-based language” is true only in terms of “JavaScript engines that use a single call stack”.
In environments where JavaScript is actually executed (browser, ‘Node.js’, etc.), it mainly uses multi-threading. Thus, in this environment, the device needed to cooperate with the JavaScript engine that uses a single call stack is called Event loop.
Run-to-completion means that once the message processing begins, no other action can’t intervene until the message processing is completed. Here is an example of Run-to-completion below.
Running the example code on the left side above, can get the result as on the right side above. (browser process may be hanged and need to be forced to close). How does this Run-to-completion method work?
In the JavaScript engine there is a place called the Call Stack that acts as a cursor indicating the location of the running code.
Whenever a request comes in, the request is sequentially placed on the Call Stack and processed.
It controls which functions are currently called and running, which functions should be called next, etc.
What happens in the call stack when the JavaScript code is executed?
check the example code below.
While executing this code, the Call stack performs following tasks:
main code are stacked on the stack.helloJsConf function is called and stacked on the stack.hello function is called and stacked on the stack.console.log ('hello') is stacked on the stack.stack.hello function is removed from the stack. 7.console.log ('JSConfKorea') is stacked on the stack.helloJSConf function is also removed from the stack after finishes the job.main block of code is removed from the stack.JavaScript runs with Call stack structure in Run-to-completion mechanism.In the same situation, what if encountering a task that takes a long time to process requests one by one?
If there is a request that takes a long time to process, such as the ’someExpensive’ function during the action, the ’hello’ or ’jsConfKorea’ message is delayed to display.
‘JavaScript’ is said to treat operations as a Single Call Stack structure.
Think about when using web services. While clicking, scrolling, and typing, data is called up and displayed on the screen.
Are those jobs actually being processed in order and waiting in turn?
Not really.
Browsers and JavaScript engines provide web APIs (setTimeout, Promise, etc...) and Event Loops to solve this concurrency problem.
Continued … All You Need To Know About Event Loop (2)