← notes

how browser builds and runs a web page

when you open a web page, the browser receives the HTML and does two things in order:

  1. build the page - read the HTML, construct a model of the page in memory, and run JavaScript it finds along the way.
  2. handle events - wait in a loop for things to happen (clicks, mouse moves, server responses), then run the right code when they do.

that is the lifecycle, everything else is detail inside those two phases.

attachments/Pasted image 20260415191230.png

phase 1 - building the page

the browser needs a model of the page

HTML is just text. the browser can't work with raw text. it needs a structured, living representation of the page that JavaScript can query and modify. that structure is called the DOM (Document Object Model).

think of the DOM as a family tree. every HTML element is a node. elements nest inside each other, forming parent-child relationships. siblings are elements at the same level with the same parent.

html
├── head
│   ├── title
│   └── style
└── body
    ├── ul#first
    └── script

one important thing: the DOM and the HTML file are not the same thing. the HTML is the blueprint. the DOM is what the browser actually builds from it and the browser will silently fix errors along the way. for example, if you put a <p> tag inside <head> (which is invalid), the browser moves it to <body> without complaining.

JavaScript runs whenever the browser hits a <script> tag

the page-building process isn't just "read HTML from top to bottom." it alternates:

  1. parse HTML → add nodes to the DOM
  2. hit a <script> tag → pause HTML parsing, run the JavaScript
  3. JavaScript finishes → resume HTML parsing
  4. repeat until there's no more HTML
attachments/Pasted image 20260415193321.png

what JavaScript can (and can't) do during page building

JavaScript runs inside a sandbox that the browser provides. the key entry point is the window object — a global object that gives JS access to everything: the DOM via window.document, browser APIs, and any global variables you create.

during page building, JavaScript can do quite a lot:

there's one important constraint: JavaScript can only touch elements that have already been parsed. if your <script> is halfway down the page, elements below it don't exist in the DOM yet. this is why developers often put <script> tags at the bottom of <body> so by that point, the entire DOM exists and is safe to query.

two types of JavaScript code

// GLOBAL CODE, runs immediately, line by line, as the browser encounters it
var list = document.getElementById("first");
addMessage(list, "Page loading");

// FUNCTION CODE, defined here, but only runs when called
function addMessage(element, message) {
  var item = document.createElement("li");
  item.textContent = message;
  element.appendChild(item);
}

global code executes automatically in sequence. function code only runs when something calls it.


phase 2 - event handling

JavaScript is single-threaded, so only one piece of code running at any given moment. the browser queues events up and processes them in order.

this is called the single-threaded execution model. it simplifies a lot of things (no race conditions, no concurrent mutation), but it has a consequence: if your event handler takes a long time to run, the entire page freezes until it finishes.

the event queue

all events go into a single event queue as they arrive. the browser's event loop continuously checks this queue and runs the handler for each event when it reaches the front.

attachments/Pasted image 20260416195412.png

the event loop does three things, forever:

  1. check the front of the queue. Is there an event?
  2. if yes — take it, run its handler all the way to completion. Nothing else runs meanwhile
  3. go back to step 1

events don't interrupt each other but wait in line. this is why a handler that runs for a long time (say, a heavy loop) will make your page feel frozen.

registering event handlers

the browser can respond to an event by registering a handler for it.

two ways of registration:

  1. property assignment - element.onclick = function() {}. simple, but limited: you can only assign one handler per event this way. a second assignment overwrites the first.
  2. addEventListener - element.addEventListener("click", function() {}). the preferred approach. you can attach as many handlers as you need for the same event, and none of them overwrite each other.

events are asynchronous

asynchronous means you don't know when it will happen. it is not predictable. so event handlers are defined in advance and the browser calls them whenever the triggering event occurs.

the four main event categories:


understanding by example

here is a concrete walktrough with a simple app.

<ul id="first"></ul>

<script>
  function addMessage(el, msg) {
    var item = document.createElement("li");
    item.textContent = msg;
    el.appendChild(item);
  }
  var first = document.getElementById("first");
  addMessage(first, "Page loading");   // runs NOW (global code)
</script>

<ul id="second"></ul>

<script>
  document.body.addEventListener("mousemove", function() {
    addMessage(document.getElementById("second"), "Event: mousemove");
  });
  document.body.addEventListener("click", function() {
    addMessage(document.getElementById("second"), "Event: click");
  });
</script>

what happens, step by step:

  1. browser parses <ul id="first"> → adds a ul node to the DOM
  2. browser hits <script> → pauses HTML parsing, runs JS:
    • defines addMessage (stored in memory, not run yet)
    • calls document.getElementById("first") → finds the ul node
    • calls addMessage(...) → creates a <li>Page loading</li> and inserts it into the DOM
  3. JS finishes → browser resumes HTML parsing
  4. browser parses <ul id="second"> → adds it to the DOM
  5. browser hits second <script> → runs JS:
    • registers a mousemove handler on document.body
    • registers a click handler on document.body
  6. no more HTML → page building complete
  7. event handling begins. the browser loops, watching the event queue.
  8. user moves mouse → mousemove event enters queue → loop picks it up → runs the handler → "Event: mousemove" appears in #second
  9. user clicks → click event enters queue → loop picks it up → "Event: click" appears in #second
  10. loop continues until the page is closed