How JavaScript Is Executed: From Parsing to Event Loop

A practical, in-depth guide explaining how JavaScript gets parsed, compiled, and executed, how the call stack and event loop manage flow, and how async work is scheduled and observed in modern engines.

JavaScripting
JavaScripting Team
·5 min read
Quick AnswerDefinition

JavaScript execution unfolds in distinct phases: parsing, compilation, and runtime. A modern engine tokenizes and parses source into an AST, then compiles hot paths with a JIT, and finally executes on a single-threaded call stack. The event loop coordinates synchronous work with asynchronous tasks via microtasks and macrotasks, ensuring responsive applications.

How JavaScript Execution Starts

When a script loads, the engine begins by tokenizing and parsing the source, building an Abstract Syntax Tree (AST). The AST guides the interpreter or compiler as it translates code into executable instructions. In many engines, a preliminary parse runs quickly to establish scope, hoisting, and syntactic structure before any actual values are computed. In this section, we walk through a simple example to illustrate the flow from source text to the first console output.

JavaScript
console.log('start'); function sum(a,b){ return a+b; } const result = sum(3,4); console.log('result:', result);

A second, short example shows how top-level statements prepare the global environment. Variables declared with let/const become part of the lexical scope, and function declarations are hoisted within their scope, affecting how the first lines execute as the script runs.

JavaScript
let x = 5; x += 10; console.log(x); // 15

Steps

Estimated time: 20-40 minutes

  1. 1

    Enable DevTools and load sample script

    Open your browser's DevTools and load the sample script from the examples above to observe parsing and initial execution in the console. This establishes the global environment and baseline behavior.

    Tip: Pin the Console or skim the Sources panel for quick context.
  2. 2

    Examine global vs local scope

    Walk through the global context creation, then enter a function to see how lexical environments and hoisting affect variable visibility.

    Tip: Use breakpoints to inspect variable bindings at different depths.
  3. 3

    Trigger async tasks and observe queues

    Run code that uses Promises and setTimeout to witness microtask vs macrotask scheduling and the order of outputs.

    Tip: Remember microtasks run before macrotasks after the current stack clears.
  4. 4

    Use debugger statements to inspect stacks

    Insert debugger; to pause execution at a critical point and view the call stack and local scope.

    Tip: Combine with console.table or console.dir for richer views.
  5. 5

    Profile hot paths and optimize

    Switch to Performance profiling to identify long-running functions and optimize hot paths or reduce allocations.

    Tip: Aim to minimize allocations inside tight loops and hot functions.
Warning: Avoid eval or Function constructors in hot paths; they prevent engine optimizations and pose security risks.
Pro Tip: Prefer let/const to avoid closure pitfalls and accidental variable leaks.
Note: Microtasks vs macrotasks shape how asynchronous code behaves; test timing across browsers.

Prerequisites

Required

Optional

  • Command line basics
    Optional

Keyboard Shortcuts

ActionShortcut
Open DevToolsIn Chrome/Edge/FirefoxCtrl++I
Open ConsoleDevTools ConsoleCtrl++J
Inspect ElementsElement PickerCtrl++C
Pause ScriptPause the debugger for the current scriptF8
Step OverMove to next line in current functionF10
Step IntoDrill into a functionF11
Step OutExit current function+F11
Refresh without CacheReload page bypassing cacheCtrl++R

Questions & Answers

What is the event loop and why does it matter in execution?

The event loop coordinates synchronous JavaScript work with asynchronous callbacks. It ensures the single thread remains responsive by queuing tasks and processing microtasks before macrotasks. Understanding it helps predict code timing and avoid race conditions.

The event loop is what coordinates all the work JavaScript does behind the scenes, including when functions run and when asynchronous tasks complete.

Is JavaScript multi-threaded?

JavaScript itself runs on a single thread, but browsers provide workers for background tasks. Outside of workers, all code executes in one thread, which is why async APIs and event-based design are important for responsiveness.

JavaScript runs on one main thread, but you can use workers for parallel tasks.

Hoisting and its effect on execution

Hoisting moves declarations to the top of their scope, but not initializations. This affects how code executes, especially with var versus let/const. It’s important to understand to avoid surprises in function scope and loops.

Hoisting means declarations are processed before code runs, which changes when variables appear in scope.

What’s the difference between var, let, and const in scope?

Var is function-scoped and can be redeclared; let and const are block-scoped, with let allowing reassignment and const preventing reassignment. Understanding scope helps prevent leaks and bugs in loops and closures.

Var is function-scoped; let and const are block-scoped, with const being immutable after assignment.

How do Promises and microtasks relate to the event loop?

Promises schedule microtasks, which run after the current call stack clears but before the next macrotask. This sequencing defines when thenCallbacks execute relative to setTimeout and other timers.

Promises run as microtasks after the current code finishes, before waiting tasks run.

Why would a modern engine optimize code with JIT?

JIT compilers identify hot paths and replace them with optimized machine code, dramatically speeding repeated operations. Deoptimization can occur if assumptions about types or shapes change at runtime.

JIT makes hot code run faster by compiling it on the fly, but may adjust if assumptions change.

What to Remember

  • Master the execution flow: parsing, compilation, running
  • Event loop governs async vs sync ordering
  • DevTools is essential for tracing stack frames and scope
  • Avoid patterns that hinder optimization (eval, dynamic code)
  • Use proper iteration variables to prevent closure issues

Related Articles