4.1 A page is not a file
This is the single shift in thinking the module asks for. The index.html you author is the root of a tree, not the whole thing. Demo Company makes the tree visible by building it one branch at a time: the home page needs only itself and a favicon; the image page adds a .webp; the CSS page adds a stylesheet; the font page adds a font discovered inside that stylesheet; the JavaScript page adds a local script and a third-party one from a CDN; the iframe page adds an entire embedded document with its own dependencies. Each page prints its own request list, so you can read the dependency tree off the screen.
4.2 Discovery: finding the dependencies
The browser learns of most dependencies while parsing, as the tokenizer and tree builder of Module 3 encounter <link>, <script>, <img>, and <iframe> elements. But discovery is not uniform. A font referenced by @font-face or a background image set in url() is invisible until the CSS itself has been fetched and parsed — the browser has to load one resource to find out it needs another. That is the amber layer in Figure 4.1, and it is why a web font often starts downloading conspicuously late.
Worse, discovery competes with the parser-blocking problem from Module 3: a synchronous <script> stops the parser, which would stop discovery of everything below it in the document. The browser's answer is the preload scanner — a secondary, lightweight pass that races ahead through the raw bytes while the main parser is blocked, finds src and href references, and starts fetching them early. Discovery order and network order are therefore not the same thing, and a good deal of browser engineering exists to make the network busy as early as possible.
4.3 The waterfall
Plot every request against time and you get the waterfall — the most important diagnostic view in web performance, and the one in your DevTools Network panel. Each bar is one resource; its horizontal position is when it started and how long it took; its vertical stacking shows what happened in parallel and what had to wait.
Two structural facts jump out of any waterfall. Parallelism is limited — over HTTP/1.1 a browser opens only a handful of connections per host, so requests queue; HTTP/2 and HTTP/3 multiplex many over one connection and largely dissolve that queue (Module 2). And chains are expensive — a resource that depends on another cannot start until the first finishes, so a three-deep chain (HTML → CSS → font) costs three sequential round trips no amount of bandwidth can collapse. The art of loading performance is turning chains into parallel fetches.
4.4 Render-blocking, async, and defer
Not all dependencies are equal in how they interrupt the page. Two behaviors dominate, and controlling them is most of what front-end performance work consists of.
CSS is render-blocking by default. The browser will not paint until it has the CSS, because painting first and restyling second would flash unstyled content at the user. So a stylesheet in the head holds back the first paint of the entire page — which is usually what you want, and is why the critical CSS should be small and fast.
Scripts choose their blocking behavior. A plain <script> is parser-blocking and ordered; the modern attributes change that:
async fetches alongside parsing and runs whenever it lands; defer fetches alongside parsing but runs in order after the document is built. For a script that touches the DOM, defer is almost always the right default. (Module-type scripts defer by nature.)4.5 Priorities, limits, and hints
The browser does not fetch the dependency tree in document order; it fetches by priority. Render-blocking CSS and the fonts needed for visible text are high priority; an image far down the page or an async analytics script is low. The browser assigns these priorities automatically from the kind of resource and where it sits, and you can nudge them: the fetchpriority attribute raises or lowers a specific request, and the resource hints — preconnect to warm up a connection, preload to start a critical fetch early, prefetch to grab something for the next navigation — let the author correct the browser's guesses. These are how you fix the “font discovered late” problem: preload it so it does not wait for the CSS.
The browser is a scheduler for the network. Priorities decide what the user sees first; hints are how the author argues with the defaults.
4.6 The critical rendering path
Out of the whole dependency tree, only a subset is required before the browser can show anything: the HTML, the render-blocking CSS, and any parser-blocking JavaScript ahead of the visible content. That subset is the critical rendering path, and shortening it — less blocking CSS, deferred scripts, preloaded essentials — is the most direct lever on how quickly a page paints. Everything outside the critical path (below-the-fold images, async scripts, non-essential fonts) can arrive afterward without delaying first paint. Demo Company's critical-render-path page exists to let you watch a single synchronous script sit squarely in that path and hold the whole page hostage until it loads and runs.
This is the bridge to Module 5. Once the critical resources are in — the DOM from Module 3 and the CSSOM built from the render-blocking CSS — the browser has everything it needs to compute styles, lay out boxes, and paint. The resource model decides when the pixel pipeline can start.
4.7 When dependencies fail
The network is not reliable terrain, and a dependency tree is only as robust as its handling of missing branches. A resource can be slow, can 404, can hang, can be blocked. A well-built page degrades rather than breaks: a failed image leaves its alt text and reserved space rather than collapsing the layout; a font that does not arrive falls back to a system face via font-display; a failed enhancement script leaves working HTML behind it. This is progressive enhancement seen from the loader's side — build the critical path so that the non-critical failing does not take the page down with it.
4.8 The lab: watch the tree grow
Walk Demo Company's resource pages in order with the Network panel open, and read each new request against this module:
image.html + cat.webp a leaf: an image referenced straight from the DOM
css.html + main.css render-blocking; holds first paint
font.html + main.css → font a chain: the font hides inside the CSS
javascript.html + app.js + cdn.js local and third-party scripts
iframe.html + embedded document a whole subtree with its own resourcesSort the waterfall by start time and watch the parallelism; sort by the dependency and watch the chains. Find the font on the font page and confirm it begins only after main.css finishes — then imagine the preload that would fix it. You are looking at the resource model's own ledger.
4.9 What you now have
The page as a dependency tree rather than a file; discovery through parsing and the preload scanner racing ahead of blocked parsing; the waterfall as the view that exposes parallelism and chains; the blocking behaviors that matter most — render-blocking CSS and the plain/async/defer choice for scripts; priorities and hints as the controls; and the critical rendering path as the subset that gates first paint. The unifying idea: the browser is a scheduler for the network, and how it orders the fetch decides how fast the page feels.
With the critical resources in hand — the DOM and the CSSOM — the browser can finally turn structure and style into something on screen. Module 5 is the pixel pipeline: computing styles, laying out boxes, painting, and compositing layers on the GPU, and the reason some changes are cheap and others force the whole machine to run again.
You wrote one file. The browser fetched a forest. Now it has to draw it.