How JavaScript Works
Learn how JavaScript code is executed from start to finish, including execution contexts, the call stack, memory creation, the execution phase, synchronous execution, and the role of the runtime environment.
Introduction
Writing JavaScript code is only the beginning. When a JavaScript file is loaded, several important processes happen behind the scenes before the program produces its final output.
JavaScript must create an environment for the program, allocate memory for variables and functions, execute statements in the correct order, manage function calls, and communicate with the surrounding runtime environment.
Understanding this process will make advanced concepts such as scope, hoisting, callbacks, promises, asynchronous programming, and the event loop much easier to understand later.
- How JavaScript code moves from a file to execution.
- What a JavaScript runtime environment is.
- What an execution context is.
- The difference between global and function execution contexts.
- How the Memory Creation Phase works.
- How the Code Execution Phase works.
- How the Call Stack manages function execution.
- Why JavaScript is called synchronous.
- Why JavaScript is called single-threaded.
- How browser APIs help with asynchronous operations.
- What the Callback Queue does.
- How the Event Loop coordinates asynchronous code.
The Big Picture
JavaScript execution involves more than simply reading one line and immediately displaying output. The source code passes through several stages and works with multiple components.
JavaScript File
↓
Runtime Environment Loads Code
↓
JavaScript Engine Processes Code
↓
Global Execution Context Created
↓
Memory Creation Phase
↓
Code Execution Phase
↓
Functions Create New Execution Contexts
↓
Call Stack Manages Execution
↓
Runtime APIs Handle External Operations
↓
Program Produces OutputEach part of this process has a specific responsibility. Together, these parts allow JavaScript applications to execute correctly.
Real-World Analogy
Imagine a restaurant kitchen. A customer places an order, the kitchen prepares a workspace, ingredients are collected, tasks are performed in order, and completed dishes are delivered.
JavaScript Code
The instructions or recipe describing what should happen.
JavaScript Engine
The chef responsible for understanding and executing the instructions.
Execution Context
The workspace containing the information needed to perform a task.
Call Stack
The system that tracks which task is currently being performed.
Runtime Environment
The complete restaurant containing additional services and resources.
Event Loop
The coordinator that checks when completed external tasks can continue.
Customer Order
↓
Recipe Received
↓
Kitchen Workspace Created
↓
Ingredients Prepared
↓
Instructions Executed
↓
Additional Tasks Managed
↓
Final Dish DeliveredFrom JavaScript File to Execution
Consider a simple JavaScript file containing variables, a function, and a function call.
const firstNumber = 10;
const secondNumber = 20;
function add(a, b) {
return a + b;
}
const result = add(firstNumber, secondNumber);
console.log(result);To produce this output, JavaScript must process the program, prepare memory, execute the global code, call the add() function, return the calculated value, and finally display the result.
Load app.js
↓
Process Source Code
↓
Create Global Environment
↓
Prepare Variables and Functions
↓
Execute Statements
↓
Call add()
↓
Calculate 10 + 20
↓
Return 30
↓
Display 30JavaScript Runtime Environment
A JavaScript runtime environment is the complete environment in which JavaScript code executes.
The runtime contains a JavaScript engine and additional features provided by the environment. A web browser is one example of a JavaScript runtime environment.
Browser Runtime Environment
│
├── JavaScript Engine
│ ├── Call Stack
│ ├── Memory Heap
│ └── Garbage Collector
│
├── Browser APIs
│ ├── DOM
│ ├── Timers
│ ├── Events
│ ├── Network Requests
│ └── Storage
│
├── Callback Queue
│
└── Event Loop- The JavaScript engine executes the JavaScript language.
- The runtime environment contains the engine and additional features.
- The browser provides APIs that are not part of the core JavaScript language.
- Different environments can provide different APIs.
Main Runtime Components
To understand how JavaScript works, you should know the main components involved in execution.
JavaScript Engine
Processes and executes JavaScript code.
Call Stack
Tracks currently executing code and function calls.
Memory Heap
Stores dynamically allocated application data.
Runtime APIs
Provide additional capabilities such as timers, DOM operations, and network requests.
Callback Queue
Stores callbacks that are ready to return to JavaScript execution.
Event Loop
Coordinates the movement of ready tasks back to the Call Stack.
What is an Execution Context?
An execution context is an internal environment created by JavaScript to manage and execute code.
You can think of an execution context as a workspace containing the information JavaScript needs while running a particular section of code.
Execution Context
│
├── Memory for Variables
├── Function Declarations
├── Scope Information
├── Current Execution State
└── Code to Execute- JavaScript code needs an environment in which to run.
- That environment is called an execution context.
- The main program receives a global execution context.
- Every function call creates a new function execution context.
Types of Execution Context
JavaScript mainly creates execution contexts for the global program and for function calls.
Global Execution Context
Created when the JavaScript program first begins executing.
Function Execution Context
Created every time a function is called.
JavaScript Program Starts
↓
Global Execution Context Created
↓
Function is Called
↓
Function Execution Context Created
↓
Function Completes
↓
Function Context RemovedGlobal Execution Context
When JavaScript begins executing a script, it creates the Global Execution Context. This is the first execution context created for the program.
const course = 'JavaScript';
const lessons = 27;
console.log(course);
console.log(lessons);The declarations and statements at the top level of the script are processed as part of the global execution context.
Script Starts
↓
Global Execution Context
↓
Create course
↓
Create lessons
↓
Display course
↓
Display lessons
↓
Script Completes- It is created when the script begins.
- Only one global execution context exists for a particular script execution.
- Global code executes inside it.
- Function calls can create additional execution contexts.
Function Execution Context
Every time a function is called, JavaScript creates a new Function Execution Context for that specific function call.
function greet(name) {
const message = 'Hello, ' + name;
return message;
}
const result = greet('Rahul');
console.log(result);Global Execution Context
│
├── Create greet()
├── Create result
│
└── Call greet('Rahul')
↓
Function Execution Context
│
├── name = 'Rahul'
├── Create message
├── Build 'Hello, Rahul'
└── Return Result
↓
Function Context Removed
↓
Global Execution Continues- Calling a function creates a new execution context.
- Calling the same function again creates another new context.
- Each call can receive different arguments.
- Each function execution has its own local data.
Two Phases of an Execution Context
A simplified model of JavaScript execution divides each execution context into two important phases.
1️⃣ Memory Creation Phase
JavaScript prepares memory for declarations before executing statements.
2️⃣ Code Execution Phase
JavaScript executes statements and updates values.
Execution Context Created
↓
Phase 1
Memory Creation
↓
Phase 2
Code Execution
↓
Execution Context Completes1. Memory Creation Phase
Before executing the program statements, JavaScript processes declarations and prepares the environment required for execution.
var firstNumber = 10;
function add(a, b) {
return a + b;
}
var result = add(firstNumber, 20);In a simplified explanation, JavaScript first prepares memory for the declared variables and function before executing the assignment statements.
Memory Creation Phase
firstNumber → undefined
add → Complete Function Definition
result → undefined- var declarations are commonly explained as receiving undefined during creation.
- let and const declarations are also created before execution.
- However, let and const cannot be accessed before their declaration is initialized.
- This behavior will be explained fully in the Hoisting lesson.
2. Code Execution Phase
After memory has been prepared, JavaScript begins executing statements in order.
var firstNumber = 10;
function add(a, b) {
return a + b;
}
var result = add(firstNumber, 20);
console.log(result);firstNumber = 10
↓
add() Already Available
↓
Call add(10, 20)
↓
Create Function Execution Context
↓
Calculate 10 + 20
↓
Return 30
↓
result = 30
↓
Display 30Example 1: How Variables Execute
var name = 'JavaScript';
var year = 1995;
console.log(name);
console.log(year);name → undefined
year → undefinedname = 'JavaScript'
↓
year = 1995
↓
console.log(name)
↓
JavaScript
↓
console.log(year)
↓
1995Example 2: How a Function Executes
function multiply(a, b) {
const result = a * b;
return result;
}
const answer = multiply(5, 4);
console.log(answer);Global Context Starts
↓
multiply() Function Available
↓
Call multiply(5, 4)
↓
Create Function Context
↓
a = 5
b = 4
↓
result = 5 × 4
↓
result = 20
↓
Return 20
↓
Function Context Removed
↓
answer = 20
↓
Display 20The Call Stack
The Call Stack is a data structure used by JavaScript to manage execution contexts.
The execution context currently at the top of the Call Stack is the one JavaScript is actively executing.
Program Starts
┌────────────────────────────┐
│ Global Execution Context │
└────────────────────────────┘
Function Called
┌────────────────────────────┐
│ Function Execution Context │ ← Running
├────────────────────────────┤
│ Global Execution Context │
└────────────────────────────┘
Function Completes
┌────────────────────────────┐
│ Global Execution Context │ ← Continues
└────────────────────────────┘Call Stack Step by Step
function greet() {
console.log('Hello');
}
greet();
console.log('Finished');┌─────────────────────┐
│ Global Context │
└─────────────────────┘┌─────────────────────┐
│ greet() Context │ ← Executing
├─────────────────────┤
│ Global Context │
└─────────────────────┘┌─────────────────────┐
│ Global Context │ ← Continues
└─────────────────────┘Call Stack
EmptyLIFO Principle
The Call Stack follows the LIFO principle: Last In, First Out.
The most recently added function execution context must complete before the previous context can continue.
Last In
↓
┌─────────┐
│ third() │ ← Removed First
├─────────┤
│second() │
├─────────┤
│ first() │
├─────────┤
│ Global │
└─────────┘
↑
First In- A new plate is placed on top.
- The top plate must be removed first.
- Function contexts work in a similar way.
- The most recently called function finishes first.
Nested Function Calls
function first() {
console.log('First Start');
second();
console.log('First End');
}
function second() {
console.log('Second Start');
third();
console.log('Second End');
}
function third() {
console.log('Third');
}
first();1. Global
2. Global → first()
3. Global → first() → second()
4. Global → first() → second() → third()
5. third() completes
6. second() continues and completes
7. first() continues and completes
8. Global continuesThe output order follows the Call Stack. When first() calls second(), first() pauses. When second() calls third(), second() pauses. After third() completes, execution returns to second(), and then back to first().
JavaScript is Synchronous
Synchronous execution means that JavaScript normally executes one statement after another in order.
console.log('Step 1');
console.log('Step 2');
console.log('Step 3');Step 1
↓
Complete
↓
Step 2
↓
Complete
↓
Step 3
↓
Complete- Statements execute in sequence.
- The current operation completes before the next synchronous operation begins.
- Long-running synchronous code can delay everything that follows it.
JavaScript is Single-Threaded
JavaScript is commonly described as single-threaded because one main Call Stack executes JavaScript code.
One Call Stack
Task A
↓
Task B
↓
Task C
↓
Task DOnly one JavaScript execution context can occupy the active top position of the main Call Stack at a time.
- Single-threaded describes the main JavaScript execution model.
- The surrounding runtime environment can perform other work.
- Browsers can handle timers, networking, rendering, and other operations outside the main JavaScript Call Stack.
- This cooperation makes asynchronous programming possible.
Blocking Code
Because synchronous JavaScript uses one main Call Stack, a long-running operation can block later code from executing.
console.log('Start');
for (let i = 0; i < 1000000000; i++) {
// Long-running work
}
console.log('End');The final statement cannot execute until the loop finishes. In a browser, extremely long synchronous work can also make the page feel frozen or unresponsive.
Start
↓
Long Operation Begins
↓
Call Stack Remains Busy
↓
Other JavaScript Waits
↓
Long Operation Completes
↓
EndAsynchronous Operations
JavaScript applications frequently need to wait for operations such as timers, user interactions, and network requests. Blocking the Call Stack during every wait would make applications inefficient.
Runtime environments provide additional systems that can handle certain operations outside the main JavaScript Call Stack.
Timers
A timer can wait outside the main Call Stack.
User Events
The browser can listen for clicks and other interactions.
Network Requests
Network operations can progress without continuously occupying the JavaScript Call Stack.
Browser Operations
The browser environment provides many capabilities beyond the core language.
Browser APIs
Browser APIs are features provided by the browser environment. They allow JavaScript to interact with webpages and request services that are not part of the core JavaScript language.
// Timer API
setTimeout(() => {
console.log('Timer Finished');
}, 1000);
// DOM API
document.querySelector('button');
// Browser Storage API
localStorage.setItem('theme', 'dark');- Variables are part of JavaScript.
- Functions are part of JavaScript.
- Arrays and objects are part of JavaScript.
- The DOM is provided by the browser.
- Browser timers are provided by the runtime environment.
- Browser storage is provided by the browser.
Callback Queue
When certain asynchronous operations complete, their callbacks may become ready to execute. Ready callbacks can wait in a queue until JavaScript is able to process them.
Asynchronous Operation Starts
↓
Runtime Handles Operation
↓
Operation Completes
↓
Callback Becomes Ready
↓
Callback Queue
↓
Wait for Call Stack- The Call Stack may already be busy.
- Ready callbacks cannot interrupt currently executing synchronous JavaScript.
- They wait until JavaScript can process them.
Event Loop
The Event Loop coordinates asynchronous execution by repeatedly checking whether the Call Stack is available and whether queued work is ready to execute.
┌─────────────────┐
│ Call Stack │
└────────┬────────┘
│
│
Is Stack Available?
│
↓
┌─────────────────┐
│ Event Loop │
└────────┬────────┘
│
↓
┌─────────────────┐
│ Callback Queue │
└─────────────────┘When the Call Stack becomes available, the Event Loop allows ready queued work to move toward execution.
- The complete asynchronous model contains additional queue types and scheduling rules.
- Promises use a different queue mechanism from traditional timer callbacks.
- Those advanced details will be easier to understand in later JavaScript lessons.
- For now, understand the relationship between the Call Stack, runtime APIs, queues, and the Event Loop.
Asynchronous Execution Example
console.log('Start');
setTimeout(() => {
console.log('Timer');
}, 0);
console.log('End');Even though the timer delay is zero, the callback does not interrupt the currently executing synchronous code.
1. console.log('Start')
↓
Output: Start
↓
2. setTimeout() Called
↓
Timer Handled by Runtime
↓
3. console.log('End')
↓
Output: End
↓
Global Synchronous Code Completes
↓
Timer Callback is Ready
↓
Event Loop Checks Call Stack
↓
Callback Executes
↓
Output: Timer- The timer callback is asynchronous.
- The current synchronous code continues first.
- The callback waits until it is allowed to execute.
- A delay of zero does not mean immediate interruption of the Call Stack.
Complete JavaScript Execution Flow
console.log('Program Started');
function calculateTotal(price, quantity) {
return price * quantity;
}
const total = calculateTotal(500, 3);
setTimeout(() => {
console.log('Timer Completed');
}, 0);
console.log('Total:', total);
console.log('Program Finished');1. Script Loaded
↓
2. Global Execution Context Created
↓
3. Memory Prepared
↓
4. Program Started Displayed
↓
5. calculateTotal() Called
↓
6. Function Context Created
↓
7. 500 × 3 Calculated
↓
8. Function Returns 1500
↓
9. Function Context Removed
↓
10. Timer Registered with Runtime
↓
11. Total: 1500 Displayed
↓
12. Program Finished Displayed
↓
13. Synchronous Code Completes
↓
14. Timer Callback Becomes Eligible
↓
15. Event Loop Coordinates Execution
↓
16. Timer Completed DisplayedJavaScript Engine vs Runtime Environment
The JavaScript engine and the runtime environment work together, but they have different responsibilities.
JavaScript Engine
Processes JavaScript syntax, creates execution contexts, manages the Call Stack, executes code, and manages memory.
Runtime Environment
Contains the engine and provides additional APIs and systems required by applications.
JavaScript Runtime
│
├── JavaScript Engine
│ ├── Execute JavaScript
│ ├── Call Stack
│ ├── Memory Management
│ └── Garbage Collection
│
└── Runtime Features
├── Timers
├── DOM
├── Events
├── Networking
├── Storage
└── Async CoordinationStack Overflow
The Call Stack has limited capacity. If functions continue calling themselves without reaching a stopping condition, the stack can grow until the environment cannot add more execution contexts.
function repeat() {
repeat();
}
repeat();Global
↓
repeat()
↓
repeat()
↓
repeat()
↓
repeat()
↓
repeat()
↓
...
↓
Maximum Stack Capacity Reached
↓
Stack Overflow Error- Recursive functions need a stopping condition.
- Every recursive call adds another function context.
- Without a base condition, the Call Stack continues growing.
Common Beginner Mistakes
- Thinking JavaScript executes code without creating an execution environment.
- Thinking the JavaScript engine and runtime environment are the same thing.
- Assuming every function shares one execution context.
- Forgetting that every function call creates a new function execution context.
- Confusing the Memory Heap with the Call Stack.
- Thinking asynchronous callbacks interrupt synchronous JavaScript immediately.
- Assuming setTimeout with zero delay executes instantly.
- Thinking browser APIs are part of the core JavaScript language.
- Forgetting that long-running synchronous code can block later execution.
- Using recursion without a proper stopping condition.
Best Practices
- Understand execution contexts before studying scope and hoisting.
- Visualize function calls using the Call Stack.
- Keep synchronous tasks reasonably short in browser applications.
- Avoid unnecessary long-running loops on the main execution thread.
- Always provide a valid stopping condition for recursive functions.
- Separate core JavaScript features from runtime-provided APIs.
- Use console output to study the order in which code executes.
- Do not assume asynchronous callbacks execute immediately.
- Learn the basic Event Loop model before moving to promises and async/await.
- Focus on the overall execution flow before studying engine-specific implementation details.
Frequently Asked Questions
What happens when JavaScript code starts running?
The runtime loads the code, the engine processes it, a global execution context is created, memory is prepared, and statements begin executing.
What is an execution context?
An execution context is the internal environment JavaScript creates to manage and execute code.
What is the Global Execution Context?
It is the first execution context created when a JavaScript script begins running.
When is a Function Execution Context created?
A new Function Execution Context is created every time a function is called.
What happens during the Memory Creation Phase?
JavaScript prepares the environment for declarations before executing the program statements.
What happens during the Code Execution Phase?
JavaScript executes statements, performs calculations, assigns values, calls functions, and produces results.
What is the Call Stack?
The Call Stack is a structure that tracks active execution contexts and determines which code is currently running.
What does LIFO mean?
LIFO means Last In, First Out. The most recently added function context is removed before earlier contexts continue.
Why is JavaScript called synchronous?
JavaScript normally executes synchronous statements one after another in order.
Why is JavaScript called single-threaded?
The main JavaScript execution model uses one primary Call Stack to execute JavaScript code.
How can JavaScript perform asynchronous tasks?
The surrounding runtime environment handles certain operations outside the main Call Stack and coordinates their callbacks with queues and the Event Loop.
What is the Event Loop?
The Event Loop coordinates when ready asynchronous work can continue after the Call Stack becomes available.
Why does setTimeout with zero delay not execute immediately?
The callback must wait until the current synchronous code finishes and the runtime scheduling process allows it to execute.
What causes a stack overflow?
A stack overflow occurs when too many execution contexts are added to the Call Stack, commonly because of uncontrolled recursion.
Key Takeaways
- JavaScript code executes inside a runtime environment.
- The JavaScript engine is responsible for processing and executing the language.
- The runtime environment provides additional features and APIs.
- JavaScript creates a Global Execution Context when a script begins.
- Every function call creates a new Function Execution Context.
- Execution contexts can be understood using a Memory Creation Phase and a Code Execution Phase.
- The Call Stack manages active execution contexts.
- The Call Stack follows the Last In, First Out principle.
- Nested function calls cause the Call Stack to grow.
- JavaScript normally executes synchronous statements sequentially.
- The main JavaScript execution model uses one primary Call Stack.
- Long-running synchronous code can block later execution.
- Runtime environments can handle certain operations outside the main Call Stack.
- Browser APIs provide features such as timers, DOM access, events, networking, and storage.
- Ready asynchronous callbacks wait until JavaScript can execute them.
- The Event Loop coordinates asynchronous work with the Call Stack.
- A zero-delay timer does not interrupt currently executing synchronous code.
- Infinite recursion can cause a maximum Call Stack error.
Summary
JavaScript execution begins when the runtime environment loads a script and the JavaScript engine processes the code. The engine creates a Global Execution Context, prepares the required memory, and then executes the program statements.
Every function call creates a separate Function Execution Context. These contexts are managed using the Call Stack, which follows the Last In, First Out principle.
JavaScript executes synchronous code using one main Call Stack. However, the surrounding runtime environment provides additional capabilities for timers, events, networking, DOM operations, and other tasks. Queues and the Event Loop help coordinate asynchronous work with the main JavaScript execution process.
Understanding execution contexts, the Call Stack, synchronous execution, runtime APIs, and the Event Loop creates the foundation for later topics such as variables, scope, hoisting, functions, events, promises, and asynchronous JavaScript.
- You understand the complete JavaScript execution overview.
- You know what a runtime environment is.
- You understand execution contexts.
- You know the difference between global and function execution contexts.
- You understand the Memory Creation and Code Execution phases.
- You know how the Call Stack manages function calls.
- You understand the LIFO principle.
- You know why JavaScript is called synchronous and single-threaded.
- You understand how blocking code affects execution.
- You know the roles of Browser APIs, the Callback Queue, and the Event Loop.
- You are ready to learn JavaScript Variables.