Event Loop in Javascript

October 11, 2020

4 min read

Javascript is a single-threaded, non-blocking, asynchronous, concurrent programming language.

  • 1 call stack + 1 heap = single-threaded language. It means that it runs only one thing at a time.
  • In asynchronous programming, when a task is being executed, you can switch to a different task without waiting for it to be completed.
  • Non-blocking operations don't block the further execution of the code until they get completed.
  • Javascript can also be non-blocking and behave as if it were multi-threaded. It means that it doesn't wait for the response of an API call or an I/O event and can continue the code execution. It is possible thanks to the JS engines which use (under the hood) real multi-threading languages, like C++ (Chrome) or Rust (Firefox). They provide us with the Web APIs under the browser hoods or ex. I/O API under Node.js.

Parallel vs. concurrent programming?

A system is said to be concurrent if it can support two or more actions in progress at the same time. A system is said to be parallel if it can support two or more actions, executing simultaneously.

Concurrency means executing multiple tasks at the same time but not simultaneously. Ex: Two tasks running in overlapping time periods, i.e., a task-2 starts running before an already running task-1 gets completed.

Parallelism means executing two or more tasks simultaneously. Ex: Running multiple calculations on a multi-core CPU at the same time.

single call stack + heap + callback queue = Concurrency Model.

Call-stack, heap and queue

Events like onChange, setTimeout, fetch etc., are not handled by the JS engine. Instead, these events are processed by various Web API's which are provided by the JS runtime environment of a browser.

A runtime environment is where your program will be executed. It determines what global objects your program can access.

Architecutre of JS Runtime Environment

V8 is Google's open-source Javascript and WebAssembly engine, written in C++. In simple terms, V8 is a C++ program that compiles and executes Javascript code.

  • The call stack and memory heap are part of the V8 engine.
  • The V8 engine provides the event loop, but this is sometimes implemented by the browser too.

1. Call Stack:

It is a data structure that records the function calls as stack frames and helps us keep track of where we are in the code so that we can run the code in order.

Primitive local variables are stored on the stack, and data structures like arrays and objects are stored in heap memory.

When a function is called, it gets pushed onto the stack, and when it returns, it gets popped off the stack.

call-stack-in-action

Without any local variables, each function call takes up 48 bytes during the execution.

When an error happens, the stack trace is written to the console. It indicates where we were in the call stack when the error happened.


2. Memory Heap

A dynamically allocated memory where objects are added and allocated.


3. Callback Queue

A javascript runtime uses a message queue - a list of messages to be processed and its associated callback.

The event loop is responsible for executing the code, collecting and processing events, and executing queued sub-tasks. It continuously checks the call stack, if it has any frames to execute, and if not, it then checks the callback queue.

while (queue.waitForMessage()) {
  queue.processNextMessage();
}

At some point during the event loop, the runtime starts handling the messages on the queue, starting with the oldest one. When the call stack is empty, the message gets removed from the callback queue, and its corresponding callback is called, with the message as an input parameter. And as always, calling a function creates a new stack frame for that function's use.

Events processed from callback queue


References