Programming Language
JavaScript
How Execute JavaScript

Execution of JavaScript – How JS Works Behind the Scenes

JavaScript is a single-threaded, non-blocking, asynchronous, and concurrent language. This means it handles tasks one at a time but allows certain operations to be executed asynchronously, enabling the main thread to remain unblocked.

JavaScript Execution Overview

JavaScript code execution involves several stages. Here’s a simplified view of how JavaScript is executed in the browser:

  1. Parsing: The JavaScript engine reads the code and parses it into an Abstract Syntax Tree (AST).
  2. Compilation: The parsed code is compiled into bytecode or machine code that the JavaScript engine can execute.
  3. Execution: The JavaScript engine executes the compiled code, producing the result.

Execution Contexts

JavaScript code is executed in various contexts, primarily:

  • Global Execution Context: The default context where any code outside of functions is executed.
  • Function Execution Context: Created whenever a function is invoked. Each function has its own execution context.
  • Eval Execution Context: Created by the eval function, though its use is discouraged due to security and performance concerns.

How JavaScript Executes Code

1. Global Execution Context

When a JavaScript file is loaded, the global execution context is created. This context includes the global object (e.g., window in browsers), the this keyword, and any global variables and functions.

2. Function Execution Context

Each time a function is called, a new execution context is created for that function. This context contains:

  • Variable Object (VO): Stores function parameters, local variables, and function declarations.
  • Scope Chain: Ensures access to variables and functions from the outer scopes.
  • this Binding: Refers to the object that called the function.

3. Execution Phases

JavaScript execution can be divided into two main phases:

  1. Creation Phase: During this phase, the JavaScript engine allocates memory and sets up the scope chain. Variable and function declarations are processed, but assignments are not yet made.
  2. Execution Phase: The code is executed line by line. Variables are assigned values, functions are called, and the code produces results.

Example Code

Here’s a simple example demonstrating the execution context:

// Global execution context
let globalVar = "I'm global";
 
function greet(name) {
  // Function execution context
  let greeting = "Hello, " + name;
  console.log(greeting);
}
 
greet("Alice");
console.log(globalVar);

Explanation

  • Global Execution Context: globalVar is declared and initialized.
  • Function Execution Context: When greet("Alice") is called, a new execution context is created with name and greeting local to the function.

Detailed Explanation of JavaScript Execution

Call Stack

The call stack is a stack data structure that keeps track of function calls. JavaScript executes code by pushing function calls onto the stack. When a function is called, it is pushed onto the stack. When the function completes, it is popped off the stack. This stack operates in a Last In, First Out (LIFO) manner.

function a() {
  console.log("Function A");
}
 
function b() {
  a();
  console.log("Function B");
}
 
b();

Call Stack Flow:

  • Push b() onto the stack.
  • Within b(), push a() onto the stack.
  • Execute a(), then pop a() off the stack.
  • Continue with b(), then pop b() off the stack.

Event Loop

The event loop is responsible for managing asynchronous operations. It continuously checks if the call stack is empty and if there are any tasks in the task queues (also known as message queues). If the stack is empty, it processes the tasks from the queues.

console.log("Start");
 
setTimeout(() => {
  console.log("Timeout");
}, 1000);
 
console.log("End");

Event Loop Flow:

  • Push console.log("Start") onto the stack and execute it.
  • Set a timer with setTimeout and move the callback to the task queue.
  • Push console.log("End") onto the stack and execute it.
  • After the call stack is empty, the event loop picks up the callback from the task queue and executes it.

Task Queues

Task queues hold the asynchronous callbacks that are waiting to be executed. There are different types of queues, such as the macro task queue (e.g., setTimeout, setInterval) and the micro task queue (e.g., Promise callbacks, MutationObserver callbacks). Micro tasks have higher priority and are processed before macro tasks.

Micro Tasks:

  • These tasks are processed before rendering and after each operation from the call stack. Macro Tasks:
  • These tasks are processed after all micro tasks are completed.
                                      +------------------------+
                                      |      Start             |
                                      +------------------------+
                                                |
                                                v
                                   +---------------------------+
                                   |     Call Stack            |
                                   | (Executes Sync Code)      |
                                   +---------------------------+
                                                |
                                                v
                      +--------------------------------------------+
                      |  Executes Synchronous Code (Line by Line)  |
                      +--------------------------------------------+
                                                |
                                                v
                  +----------------------------+----------------------------+
                  |                             |                            |
                  v                             v                            v
    +--------------------------+   +--------------------------+   +--------------------------+
    | Sync Code Block (Task 1) |   | Async Task (API Call)    |   | Sync Code Block (Task 2) |
    +--------------------------+   | (e.g., HTTP Request)     |   +--------------------------+
                  |                  +------------------------+                |
                  v                            |                             v
        +------------------+                  |                    +------------------+
        | Task Completed   |                  |                    | Task Completed   |
        +------------------+                  v                    +------------------+
                                        +--------------------+
                                        | Worker Thread Pool |
                                        | (Handles Async)    |
                                        +--------------------+
                                                 |
                                                 v
                                +-----------------------------+
                                | System APIs / Libuv Threads |
                                | (Handles I/O, FS, Network)  |
                                +-----------------------------+
                                                 |
                                                 v
                                     +-------------------------+
                                     |      Callback Queue     |
                                     | (Async Tasks Waiting)   |
                                     +-------------------------+
                                                 |
                                                 v
                                       +---------------------+
                                       |      Event Loop     |
                                       +---------------------+
                                                 |
                                                 v
                             +-------------------------------------+
                             | Checks if Call Stack is Empty       |
                             | Processes Callbacks from Queues     |
                             +-------------------------------------+
                                                 |
                                                 v
                             +-------------------------------------+
                             | Moves Async Callbacks to Call Stack |
                             | Prioritizes Microtasks over         |
                             | Macrotasks                          |
                             +-------------------------------------+
                                                 |
                                                 v
                                  +-----------------------------+
                                  |   Executes Async Callback   |
                                  +-----------------------------+
                                                 |
                                                 v
                                        +----------------+
                                        |      End       |
                                        +----------------+

How It Works:

  • Call Stack: Executes synchronous code. When function calls are made, they are pushed onto the stack and executed in order.
  • Event Loop: Continuously checks if the call stack is empty and processes tasks from the task queues.
  • Task Queues: Hold asynchronous callbacks waiting to be executed. Micro tasks are given priority over macro tasks.
  • Processing: Once the call stack is empty, the event loop processes tasks from the queues and updates the UI if necessary.