Lesson 21 / 24
Network Panel Diagnostics
Which cause a request's timing stages point to; the distinction between transferred size and resource size, headers' role in diagnosis, reading a dependency chain in the waterfall, and making a measurement reproducible.
Contents
The previous lesson answered why an element looks the way it does, not why its content is what it is. If the number on the badge is stale, the problem is not in the style: either the request was never made, it was served from cache, the server returned stale data, or the response arrived much later than expected.
The Network panel separates these four possibilities. This lesson covers the measures the panel produces and which cause each measure points to.
The Questions the Panel Answers
The panel shows a list of requests, and every row carries an answer to four questions.
Was the request actually made? A request not in the list was never made. An expected request never showing up says the code never ran that path, or a condition was not met — there is no need to look at the server.
Where was it served from? Whether it came from the network, the browser’s own cache, or a service worker is marked separately. A cache-served request appears in the list but never reached the network; this is the most common source of the stale-data problem.
How long did it take, and where did it wait? Total time alone is not a diagnosis; its breakdown into stages is.
What did it return? Status code, headers, body. Most wrong-content problems show up here.
The Stages of Timing
A request’s total time splits into consecutive stages, and each stage taking longer points to a different cause.
Queued time is the time before the request has started at all. The browser limits how many simultaneous connections it opens to the same host; once that limit fills, new requests wait. A long queue says something about how many requests the page starts at once, not about the server.
Connection setup consists of name resolution, transport connection, and the secure handshake. It shows up only on new connections; on a persistent connection it is near zero. Taking longer points to network distance and certificate verification, not server load.
Waiting for first byte is the time between the request being sent and the first response byte arriving, including the server’s time to produce the response. Taking longer here moves the diagnosis to the server side; there is nothing to do on the client.
Downloading the body is the time from the first byte to the last. Taking longer relates to size or bandwidth; compression and minification affect this, server speed does not.
The distinction is measurable. The following server produces two delays separately: a processing time up to the first byte, then a transfer time for the rest of the body.
// delayed-server.mjs — waits 300 ms until the first byte, then 200 ms for the rest of the body import { createServer } from "node:http"; const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); createServer(async (request, response) => { response.sendDate = false; await wait(300); // the server's processing time: delays the first byte response.writeHead(200, { "Content-Type": "application/json" }); response.write('{"measurements":[{"temperature":-4.2}'); await wait(200); // the rest of the body: extends the download time response.end(',{"temperature":-4.6}]}'); }).listen(8138, "127.0.0.1", () => console.log("listening: 127.0.0.1:8138"));
#!/usr/bin/env bash # Starts delayed-server.mjs, measures one request's stage timings, then stops it. node delayed-server.mjs > /dev/null & server=$! sleep 1 curl -sS -o /dev/null http://127.0.0.1:8138/measurements.json \ -w 'name lookup : %{time_namelookup} s connect : %{time_connect} s first byte : %{time_starttransfer} s total : %{time_total} s downloaded : %{size_download} bytes ' kill "$server"
name lookup : 0.000152 s connect : 0.000438 s first byte : 0.306938 s total : 0.508153 s downloaded : 60 bytes
Times depend on the environment and vary in decimal places from run to run; what does not change is the structure. Name resolution and connection setup are too short to measure, since the request went to the loopback address; on a real server, these two values take a noticeable share of the total. The first-byte time reflects the 300 milliseconds the server held back. The roughly 200-millisecond gap after it is body download.
The diagnostic rule follows: the time up to the first byte and the time after it measure two separate problems, and a single total number hides both.
Transferred Size and Resource Size
The panel shows two sizes for a request. Transferred size is the bytes that went over the wire; it includes headers and, if compressed, is the compressed form. Resource size is the content’s size once unpacked.
Their ratio says whether compression is working. Equal sizes show compression was not applied — for a text-type resource, a configuration gap. Transferred size near zero shows the request was served from cache.
The distinction matters for performance too. Parsing cost is proportional to resource size, transfer cost to transferred size. Compression lowers the second, not the first: a large script that compresses well does not tire the network, but it does tire the main thread.
Reading Headers
Response headers are the evidence for the previous topic’s freshness decision. Why a resource arrived stale is answered by reading the caching permission and lifetime headers; if a validator exists, whether a conditional request was made and an empty-body response came back is visible in the list.
Three more headers come up often. Content type determines how the browser interprets the response; a wrong type causes a correctly arrived response to be processed incorrectly. Content encoding says in which form compression was applied. The header declaring which request header the response varies by keeps the cache from serving the same response to different users; its absence lets one user’s response reach another.
Request headers are read too: whether credentials were sent, whether a conditional request carried a validator, and which origin made the request.
Reading a Chain in the Waterfall
The waterfall view shows every request as a bar on a timeline. What is read is not individual durations, it is the bars’ position relative to each other.
Bars starting side by side are parallel requests. If one does not start until another finishes, there is a dependency between them, usually unwanted: a resource discovered only after a script has downloaded and run can only be requested at that point. The preload scan from the Resource Loading Order lesson exists to shorten this chain; a staircase pattern says the scan could not see the resource.
Bars starting together but waiting a long while point to a connection limit. Resources holding up first render are compared against timeline markers: a request finishing after first contentful paint did not delay that render.
An Intervening Layer’s Appearance in the List
When a service worker is registered, the list can double. The page’s own request produces one row; if the worker goes to the network to fulfill it, that appears as a second row. Both rows belong to the same address, and confusing them makes the request count look doubled.
The distinction is the diagnosis itself. If the page’s row marks the request as served from the worker with no network row beneath it, the response came from cache. If both rows are present, the worker went to the network; the gap between their durations is its own processing time. If the page’s row appears but the worker never engages, either the request is out of scope or the page is not yet controlled — the control rule from the Service Workers lesson becomes observable here.
The worker’s own lifecycle leaves a trace in the list too: the update request for the worker script itself and the requests for resources collected during install show up as rows the page never asked for.
Reproducible Measurement
Network measurement cannot be compared until measurement conditions are fixed. Three conditions need to be stated explicitly.
Cache state. A first visit and a repeat visit are two completely different scenarios, and both are real. Whichever the measurement is for, that state is set up; measuring with cache disabled describes only the first visit.
Network condition. Tools can artificially limit bandwidth and latency. A local measurement on a development machine never represents a field user’s conditions; throttling is the only client-side way to bring it closer to reality.
Extensions and background activity. Installed extensions mix their own requests into the list and affect timing. Measurement is done in a profile with none.
The recording itself needs preserving too: the list clears on navigation by default, and the record of a problem that results in navigation is lost with it. Preserving the log is requested explicitly.
Summary
- The Network panel separates four questions: was the request made, where was it served from, how long did it wait at which stage, what did it return. Stages point to different causes: queueing to the page’s request count, connection setup to distance, first byte to the server, download to size.
- With a service worker registered, the same address can produce two rows; the absence of the second row shows the response came from cache.
- The gap between transferred size and resource size measures compression; parsing cost is proportional to resource size.
- Headers are the evidence for the freshness decision, content interpretation, and cache separation.
- What is read in the waterfall is not durations but the bars’ position relative to each other; a staircase pattern means a discovery chain.
- A measurement cannot be reproduced without fixing cache state, network condition, and browser profile.
Next Step
The Network panel says when a request finished, not why the page still stays frozen after the response arrives. If the measurement list downloaded but the screen updates late, the cause is not the network but work queued on a single thread: parsing, style calculation, layout, painting, and every intervening script share the same queue. Where it gets stuck is seen not from the request list but from a breakdown of work over time. The next lesson covers the recording that produces this breakdown and how to read it.
To keep your progress and take notes, Log in
My notes
Log in to take notes.