How JavaScript Works

JavaScript is a single-threaded, event-driven language that handles multiple tasks efficiently through mechanisms like the event loop, Web APIs, and various queues. Let’s break down the inner workings of JavaScript step-by-step.

1. Single-Threaded Execution

  • JavaScript executes one command at a time.
  • It uses a single thread to perform all its operations.
  • Each function call creates an execution context that enters the call stack.

2. Call Stack

  • The call stack is a data structure used to manage the sequence of function calls and their execution contexts.
  • When a function is invoked, it gets pushed onto the call stack.
  • When the function execution completes, it gets popped off the call stack.

3. Event Loop

  • The event loop is a mechanism that ensures non-blocking operations.
  • It continuously checks the call stack and the task/microtask queues.
  • The event loop prioritizes the microtask queue over the task queue.

4. Web APIs

  • Web APIs provide functionalities like making network requests, handling timers, and more.
  • These APIs operate outside the call stack in the browser environment.
  • They handle long-running tasks and avoid blocking the main thread.

5. Task Queue and Microtask Queue

  • Task Queue: Used for callback-based APIs like setTimeout.
  • Microtask Queue: Used for promise-based operations.
  • The event loop processes the microtask queue before the task queue.

Example 1: Callback-Based Using setTimeout

console.log(‘Start’);
setTimeout(() => { console.log(‘100ms’); }, 100);

console.log(‘End’);

Explanation:

console.log(‘Start’);:
Pushed to the call stack and executed, printing “Start”.
Call stack is now empty.
setTimeout(() => { console.log(‘100ms’); }, 100);:
Pushed to the call stack.
setTimeout is a Web API, setting a timer in the browser environment.
The callback is registered to run after 2000 milliseconds.
The setTimeout call is popped off the call stack.
console.log(‘End’);:
Pushed to the call stack and executed, printing “End”.
Call stack is now empty.
Event Loop:
After 2 seconds, the timer expires, and the callback is moved to the task queue.
The event loop moves the callback to the call stack when it is empty.
The callback executes, printing “This is a callback”.
Example 2: Promise-Based Using Fetch API
console.log(‘Fetching data…’);

fetch(‘https://api.example.com/data’)

.then(response => response.json())

.then(data => console.log(data))

.catch(error => console.error(‘Error:’, error));

console.log(‘Fetch initiated’)

 

Example 2: Promise-Based Using Fetch API
console.log(‘Fetching data…’);

fetch(‘https://api.example.com/data’)

.then(response => response.json())

.then(data => console.log(data))

.catch(error => console.error(‘Error:’, error));

console.log(‘Fetch initiated’);

Explanation:

console.log(‘Fetching data…’);
Pushed to the call stack and executed, printing “Fetching data…”.
Call stack is now empty.
fetch(‘https://api.example.com/data’):
Pushed to the call stack.

fetch is a Web API, making a network request in the browser environment.
A promise is returned, and handlers are registered.

The fetch call is popped off the call stack. console.log(‘Fetch initiated’) Pushed to the call stack and executed, printing “Fetch initiated”. Call stack is now empty.

Event Loop:The network request is processed asynchronously. When the request completes, the promise resolves or rejects. The .then and .catch handlers are placed in the microtask queue.

Microtask Queue: The event loop processes the microtask queue first. The first .then handler processes the response and returns another promise.
The second .then handler prints the data or handles errors. The .catch handler manages any errors during the fetch.