When a web page does something interactive — a menu slides open, a form warns you about a missing field, a number on a dashboard updates without reloading — that behavior comes from JavaScript. But JavaScript on its own is just text. Something has to read that text, understand it, and actually carry out the instructions. That something is the browser.
This article is about the browser’s role as the thing that runs your scripts. We won’t teach the JavaScript language itself here — no loops, no variables, no syntax. Instead we’ll look at what happens behind the scenes: how the browser turns a file full of code into a working, living page, why it can only really do one thing at a time, and how the way you load a script changes what your visitor sees and when.
What actually runs your JavaScript
Inside every modern browser there is a piece of software called a JavaScript engine. Think of it as a translator and worker rolled into one: it reads the JavaScript you wrote and figures out how to make the computer do it.
Different browsers ship different engines. Chrome and the many browsers built on the same core use one called V8. Firefox uses SpiderMonkey. Safari uses JavaScriptCore. You don’t choose the engine — it comes baked into the browser — but it’s useful to know it exists, because the engine is the real “brain” doing the heavy lifting.
Here’s the rough journey a script takes from text to action:
your .js file (plain text)
│
▼
1. PARSING → engine reads the code and builds a
structured map of what it means
│
▼
2. COMPILING → that map is turned into fast,
machine-level instructions
│
▼
3. RUNNING → the instructions execute; the page
reacts (DOM changes, data loads, etc.)
Let’s unpack those three steps in plain terms.
Parsing: reading and understanding the code
Parsing is the engine reading through your code character by character and checking that it makes sense. It groups the text into meaningful pieces — this is a function, this is a name, this is a value — and builds an internal tree that represents the structure of the program. If you’ve ever forgotten a closing bracket and seen a “syntax error”, that’s the parser telling you it couldn’t make sense of what you wrote.
Compiling: turning code into something fast
A computer’s processor doesn’t speak JavaScript. It speaks a much lower-level language. So after parsing, the engine compiles your code — it translates the structured version into instructions the machine can run quickly.
Modern engines are clever about this. They use an approach often called just-in-time compilation, which means they compile code right before it’s needed and keep optimizing the parts that run a lot. You don’t have to do anything to trigger this; it happens automatically every time a page loads.
Running: making the page do things
Finally the engine runs the compiled instructions. This is where the visible action happens: a script might read what you typed, change some text on the page, fetch new data from a server, or start an animation. Running JavaScript is also how a page stays “alive” after it first loads.
The engine is part of the browser, not the page
The JavaScript engine ships inside the browser, the same way a calculator app is part of your phone. A web page just hands the browser some code; the browser’s engine is what reads and executes it. This is why the same script can behave slightly differently across browsers — they use different engines.
One thing at a time: the single main thread
Here is one of the most important ideas for a beginner to grasp: in a web page, your JavaScript normally runs on a single main thread. A “thread” is just a line of work the computer follows. Single-threaded means there is one line, and tasks wait their turn.
A helpful analogy: imagine a small shop with one cashier. Customers (tasks) line up. The cashier handles one customer completely, then calls the next. The cashier is fast, so it usually feels instant — but if one customer needs something that takes a long time, everyone behind them waits.
That cashier is your page’s main thread. And it has a second job: this same thread is also responsible for drawing the page and responding to clicks. So if your JavaScript starts a long, heavy task and refuses to finish, the page freezes — buttons stop responding, scrolling stutters — because the one worker is busy and can’t get to anything else.
Why pages freeze
A frozen or unresponsive page is almost always a sign that JavaScript is hogging the main thread with a task that takes too long. Since the same thread also handles drawing and clicks, nothing else can happen until that task ends. Keeping work small and quick is what keeps a page feeling smooth.
The event loop: how one thread juggles so much
If there’s only one worker, how does a page do many things at once — wait for data, respond to clicks, and run a timer — without falling apart? The answer is a system called the event loop.
The idea is simple. Some tasks take time but don’t need the main thread the whole while — for example, asking a server for data, or waiting three seconds before doing something. The browser hands these off to be worked on elsewhere and lets the main thread keep going. When one of those tasks is finished, its follow-up work is placed in a queue — a waiting line. The event loop is the part that watches this line: whenever the main thread is free, it picks the next item from the queue and runs it.
Main thread: [ run code ] → [ free? ] ──┐
│ yes
Queue: [ task ][ task ][ task ] ──┘ take the next one
▲
│ finished background work drops new tasks here
(a server replied, a timer fired, you clicked something)
So the page never truly does two things at the exact same instant on the main thread — it just switches between small jobs so quickly that, to you, it feels simultaneous. This is why a well-built page can load data in the background while still responding instantly to your scrolling and clicking.
You don’t need to manage the event loop yourself; it’s built into the browser. But knowing it’s there explains a lot — like why something you asked for “later” runs only after the current task finishes.
How loading a script affects the page
Now let’s connect JavaScript to what the reader actually sees. To show a page, the browser reads the HTML from top to bottom and builds the page structure as it goes. When it meets a <script> tag, it has a decision to make — and that decision changes how fast your page appears.
There are three common ways to include a script, and the difference matters:
| Method | What the browser does | Effect on the page |
|---|---|---|
Normal <script> |
Stops building the page, fetches the script, runs it, then continues | Page can appear blank or stuck while the script loads — this is “render-blocking” |
<script async> |
Keeps building the page; runs the script as soon as it arrives, even mid-build | Faster, but scripts may run in an unpredictable order |
<script defer> |
Keeps building the page; waits and runs scripts in order after the page is built | Page appears quickly, scripts run in order — usually the safest default |
Here’s what those look like in HTML:
<!-- Render-blocking: building pauses here until this finishes -->
<script src="app.js"></script>
<!-- Async: fetched alongside the page, run whenever it's ready -->
<script async src="analytics.js"></script>
<!-- Defer: fetched alongside the page, run in order after build -->
<script defer src="app.js"></script>
The plain-language takeaway: a normal <script> in the middle of your page can make a visitor stare at an unfinished screen, because the browser stops laying out the page to deal with the script first. Using defer (or placing scripts at the very end of the page) lets the content show up first, then the JavaScript runs. For a beginner, defer is a reliable choice most of the time.
A simple rule of thumb
If a script changes how the page looks or works and the order matters, defer is usually the friendliest option: the page shows up fast and your scripts still run in the order you wrote them. Reach for async mainly for independent, fire-and-forget scripts like analytics.
JavaScript can change the page after it loads
A page is not frozen the moment it appears. Behind the scenes the browser keeps a live, in-memory model of the page called the DOM (Document Object Model) — essentially a structured representation of every element on the page. JavaScript can read and change this model at any time.
When a script adds a paragraph, hides a menu, or updates a price, it’s editing the DOM. The browser notices the change and re-draws the affected part of the page so you see the result. That’s the whole reason a single page can feel like an app: the structure was drawn once, and JavaScript keeps editing it in response to what you do.
This ties directly into the browser’s rendering path — the sequence of steps the browser follows to turn HTML and styles into pixels on screen. JavaScript sits inside that path: it can change the structure or styling, which forces the browser to recalculate and re-paint. Doing that constantly and carelessly is one common cause of a sluggish page, because each change asks the browser to do visual work again.
HTML + CSS → browser draws the page → you see it
▲
│ JavaScript edits the DOM
│ (add, remove, change elements)
└── browser re-draws what changed
A quick recap
You started this article seeing JavaScript as mysterious behavior on a page. Now you can see the machinery behind it:
- The JavaScript engine inside the browser parses, compiles, and runs your code — turning plain text into real actions.
- Your scripts run on a single main thread, so tasks wait their turn; a long task can freeze the page because the same thread also draws and listens for clicks.
- The event loop lets that one thread juggle many jobs by queuing finished background work and running it when the thread is free.
- How you load a script — normal,
async, ordefer— changes how quickly your page appears, withdeferbeing a safe default. - JavaScript keeps the page alive by editing the DOM, prompting the browser to re-draw what changed.
The natural next step is the JavaScript language itself — the actual variables, functions, and logic you write, which is covered separately under the frontend topics. With the picture in this article, you’ll understand not just what that code says, but how the browser brings it to life.