Event Loopcritical

Call Stack

The call stack is a LIFO data structure that tracks the currently executing function. Each function call pushes a frame; return pops it. When the stack is empty, the event loop can push new work.

Memory anchor

The call stack is a stack of plates at a buffet — you can only wash (execute) the top plate. Drop a plate (error) and everything above it crashes down until someone catches it.

Expected depth

JavaScript is single-threaded — only one execution context runs at a time. The call stack holds stack frames containing the function's local variables, arguments, and the return address. Synchronous exceptions unwind the stack until a catch block is found or the error reaches the top (uncaught exception). Stack overflow occurs when recursion exceeds the engine's maximum call stack depth (typically ~10,000 frames in V8).

Deep — senior internals

Each stack frame corresponds to an Execution Context containing a Variable Environment, Lexical Environment, and ThisBinding. V8 uses a fixed-size C++ stack for native frames and a separate JavaScript frame stack. The stack is inspectable via Error.stack, which V8 captures lazily using shadow stacks to avoid overhead on the happy path. Tail call optimization (TCO) was in ES2015 spec but only Safari implements it — don't rely on it in Node or Chrome. For infinite recursion patterns, use trampolining: return a thunk instead of recursing, and have a trampoline loop that calls it, keeping the stack flat.

🎤Interview-ready answer

The call stack is a LIFO structure tracking active function calls in a single-threaded JS runtime. Each invocation pushes a new execution context; return pops it. When the stack is empty, the event loop picks the next task. Stack overflow happens when recursion is too deep — the fix is either iteration or trampolining.

Common trap

Async functions do NOT block the call stack — await suspends the async function and releases control back to the event loop, allowing other code to run. Many engineers think await 'blocks' like a sleep, which leads to misunderstanding why UI stays responsive during await.

Related concepts