How Browsers Read and Execute JavaScript Code
Understand how a browser loads, parses, compiles, and executes JavaScript. Learn the full pipeline from script tag to running code.
Understanding how browsers execute JavaScript means tracing everything that happens between the browser seeing a <script> tag and your code actually running. This pipeline helps you write faster-loading code and debug problems.
The Full Pipeline
Each step in this pipeline has a specific job. Let us walk through them one at a time.
Step 1: HTML Parsing and the Script Tag
The browser starts by downloading and parsing the HTML. It builds a tree-like structure called the DOM (Document Object Model) that represents every element on the page.
When the parser hits a <script> tag, it stops. By default, the browser pauses DOM construction, downloads the script, and runs it before continuing. This is why a slow-loading script can make a page appear blank.
<!-- This blocks page rendering until script.js loads and runs -->
<script src="script.js"></script>
<!-- This downloads in parallel and runs when HTML is fully parsed -->
<script src="script.js" defer></script>
<!-- This downloads in parallel and runs as soon as it is ready -->
<script src="script.js" async></script>defer is usually the right choice for scripts that interact with the DOM. The script downloads in the background while HTML parsing continues, then runs after the DOM is complete. async is good for independent scripts like analytics that do not depend on the page structure.
Step 2: Parsing, Source Code to AST
Once the script is downloaded, the JavaScript engine parses the text into an Abstract Syntax Tree (AST). An AST is a structured representation of your code that the engine can work with.
Take this line:
const x = 2 + 3;Before building the tree, the parser first breaks the line into individual tokens, each one labeled with what kind of syntax element it represents:
Keyword: const
Identifier: x
Operator: =
Number: 2
Operator: +
Number: 3
Punctuation: ;These tokens are then arranged into a tree structure that represents the meaning: "declare a constant variable named x and assign it the result of adding 2 and 3."
If the parser finds invalid syntax, it throws a SyntaxError and the script does not run at all. This is why a missing parenthesis on line 100 can prevent line 1 from executing.
Step 3: Compilation, AST to Bytecode to Machine Code
Modern JavaScript engines use a technique called Just-In-Time (JIT) compilation. This happens in layers:
The interpreter starts by running code immediately from bytecode. When it detects a function being called many times (a hot path), the optimizing compiler recompiles that function into highly optimized machine code.
If the optimizer made assumptions that later turn out to be wrong, for example if it assumed a function always receives numbers but then gets a string, it deoptimizes back to baseline code. This is called a deopt, and it is why you should avoid changing the types of variables frequently.
Step 4: Execution
Once compiled, the code runs. The engine manages:
- The call stack, which tracks which function is currently running
- The memory heap, which stores variables and objects
- The garbage collector, which frees memory that is no longer needed
JavaScript is single-threaded, meaning it does one thing at a time on the main thread. Long-running JavaScript blocks the page. This is why async patterns like timers, fetch, and animation frames are important: they schedule work for later without blocking the current task.
What Happens When There Is an Error
Syntax errors are caught during parsing. The script never runs.
console.log("This will not print");
const x = ; // SyntaxError: Unexpected tokenRuntime errors are different. They happen during execution rather than parsing, so any code before the error still runs normally, and only the code after it is skipped:
console.log("This prints"); // This runs
undefinedFunction(); // ReferenceError: not defined
console.log("This does not"); // This never runsThe browser logs the error to the Console, including the line number and a stack trace showing the chain of function calls that led to the error.
Where Script Placement Matters
Where you put your <script> tags affects when your code runs and what it can access:
| Placement | When It Runs | Can Access DOM? | Blocks Rendering? |
|---|---|---|---|
| Head, no attributes | Immediately, before body | No | Yes |
| End of body | After body parsed | Yes | Minimal |
| Head, with defer | After HTML fully parsed | Yes | No |
| Head, with async | As soon as downloaded | Maybe not | No |
The safest default for your own scripts is a <script> tag with the defer attribute in the head, or a plain script tag at the end of the body.
JavaScript Engines by Browser
| Browser | Engine | Notable For |
|---|---|---|
| Chrome, Edge, Opera | V8 | Also used in Node.js, Deno, and Electron |
| Firefox | SpiderMonkey | First JS engine ever, created by Brendan Eich |
| Safari | JavaScriptCore (Nitro) | Also used in Bun runtime |
| Legacy IE | Chakra | Microsoft's engine, now retired |
All engines implement the same ECMAScript specification. They produce the same results for valid JavaScript. They differ mainly in performance characteristics and which experimental features they support early.
For a deeper look at what happens after the browser loads JavaScript, read about how JavaScript works in the browser, which covers the event loop, call stack, and async execution. To practice running JavaScript in both environments, see how to run JavaScript in the browser and Node.js.
Rune AI
Key Insights
- Browsers parse HTML and pause when they hit a script tag to load and run JavaScript.
- The JS engine parses source code into an AST (Abstract Syntax Tree).
- JIT compilation converts JavaScript to optimized machine code at runtime.
- Place scripts at the bottom of the body or use defer to avoid blocking page rendering.
- Different browsers use different JS engines (V8, SpiderMonkey, JavaScriptCore).
Frequently Asked Questions
Does JavaScript run while the page is loading?
What is just-in-time (JIT) compilation?
Why do different browsers run JavaScript at different speeds?
Conclusion
When a browser encounters a script tag, it downloads the code, parses it into an abstract syntax tree, compiles it to bytecode and optimized machine code through JIT compilation, and finally executes it. This entire pipeline happens in milliseconds for most scripts. Understanding this process helps you write code that loads faster and avoid common performance pitfalls.
More in this topic
Is JavaScript Frontend or Backend? Full Guide
JavaScript is both a frontend and backend language. Learn the difference between browser JavaScript and Node.js, what each is used for, and which one you should learn first.
Learn JavaScript Step by Step Tutorial with Real Examples
Follow a hands-on tutorial that teaches JavaScript by building a real interactive page. Write your first variables, functions, and event listeners with examples you can run.
JavaScript Tutorial: Complete Beginner's Guide to Programming in 2025
A structured learning path for absolute beginners. Learn what to study first, how to practice, and which JavaScript concepts matter most when you are starting from zero.