Online Compiler logoOnline Compiler

JavaScript Tutorial

How JavaScript Works: From Engine to Event Loop (Beginner to Advanced Guide)

JavaScript powers everything from simple button clicks to large-scale web applications. If you understand what happens behind the scenes when code runs, you debug faster, write cleaner asynchronous logic, and perform much better in technical interviews.

Why this matters

Once you understand engine behavior, execution context, call stack, and event loop, JavaScript stops feeling magical and starts feeling logical.

JavaScript Is Single-Threaded, But Not Slow

JavaScript executes one task at a time on the main thread. That means one call stack and one active instruction at any moment.

It still handles real-world workloads efficiently because asynchronous operations are non-blocking and coordinated through the event loop.

  • One call stack
  • One instruction executed at a time
  • No parallel execution in the main thread

The JavaScript Engine

JavaScript runs inside an engine that parses, compiles, and executes code while managing memory.

  • V8 (Chrome, Node.js)
  • SpiderMonkey (Firefox)
  • JavaScriptCore (Safari)
  • Modern engines use Just-In-Time compilation for high performance.

How JavaScript Executes Code

Execution happens in two phases: memory creation phase and code execution phase.

  • Creation phase: memory allocated for variables/functions, global execution context created.
  • Execution phase: code runs line by line, values assigned, functions invoked.
  • Hoisting is explained by work done during creation phase.

Execution Context Explained

Every running unit of JavaScript code has an execution context.

  • Global Execution Context
  • Function Execution Context
  • Eval Execution Context (rarely used)
  • Each context has variable environment, scope chain, and this binding.

The Call Stack

JavaScript uses a call stack to manage execution contexts in order.

  • Function call -> pushed onto stack
  • Function finish -> popped from stack
  • Ensures correct and predictable execution order

The Event Loop and Async JavaScript

Asynchronous tasks like timers, fetch, and events are handled through browser APIs and queues.

The event loop continuously checks whether the call stack is empty and then schedules queued callbacks.

  • Synchronous code runs first
  • Async operations are delegated to Web APIs
  • Completed callbacks are queued
  • Event loop moves callbacks to stack when stack is empty

What Are Web APIs?

Web APIs are browser-provided capabilities, not part of core JavaScript language syntax.

  • DOM API
  • setTimeout / setInterval
  • fetch
  • Geolocation
  • LocalStorage

Microtasks vs Macrotasks

Async callbacks are scheduled in different queues with different priority levels.

  • Microtasks: Promise callbacks, queueMicrotask, MutationObserver
  • Macrotasks: setTimeout, setInterval
  • Microtasks run before macrotasks after main execution completes

JavaScript Memory Model

JavaScript memory is generally discussed in terms of stack and heap.

  • Stack: primitive values, function calls
  • Heap: objects, arrays, functions
  • Garbage collection cleans unused memory automatically

Why This Knowledge Is Critical

Most advanced JavaScript interview questions revolve around internals like event loop, call stack, execution context, hoisting, and closures.

  • Debug unexpected behavior faster
  • Avoid blocking the main thread
  • Write optimized async code
  • Understand scope and closures deeply

Summary

JavaScript uses a single-threaded model supported by execution contexts, call stack, Web APIs, callback queues, and the event loop.

The engine creates memory, executes line by line, and coordinates async work without blocking the main thread.

Code Examples

Creation Phase and Hoisting

console.log(x);
var x = 5;

// During creation phase:
// x is allocated and initialized as undefined
// During execution phase:
// x becomes 5

Variables declared with var are hoisted and initialized as undefined during memory creation phase.

Call Stack Flow

function first() {
  second();
}

function second() {
  console.log("Hello");
}

first();

Global context -> first() pushed -> second() pushed -> log executes -> second pops -> first pops.

Event Loop with setTimeout

console.log("Start");

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

console.log("End");

Output order is Start, End, Inside Timeout because timer callback runs only after the call stack is clear.

Microtask vs Macrotask Priority

console.log("Start");

Promise.resolve().then(() => {
  console.log("Promise");
});

setTimeout(() => {
  console.log("Timeout");
}, 0);

console.log("End");

Output: Start, End, Promise, Timeout. Promise callback is a microtask and runs before timer macrotask.

Common Mistakes and Fixes

Assuming setTimeout runs immediately

It schedules a callback; execution depends on queue order and stack availability.

Ignoring creation phase behavior

Understand hoisting and execution context before debugging scope issues.

Treating all async callbacks equally

Learn microtask vs macrotask priority to predict execution order correctly.

Frequently Asked Questions

Is JavaScript single-threaded?

Yes, JavaScript runs on a single main thread with one call stack.

If it is single-threaded, how does async work?

Async tasks are handled by Web APIs and queues, then coordinated back through the event loop.

Why do Promises run before setTimeout?

Promise callbacks are microtasks, and microtasks are processed before macrotasks like setTimeout.

Do I need this for interviews?

Yes. Event loop, call stack, execution context, hoisting, and closures are common interview topics.

Related JavaScript Topics