5 exercises — TTFB and Network panel timing, long tasks in the Performance panel, flame chart axes, Memory heap snapshots (shallow vs retained size), and stalled network requests.
0 / 5 completed
1 / 5
A performance report says: "High TTFB on the homepage is delaying all subsequent resource loads." What does TTFB measure in the Network panel?
TTFB — Time To First Byte:
TTFB is one of the most important metrics in the Network panel's Timing tab for each request.
What TTFB includes: • DNS lookup — resolving the domain to an IP address • TCP connection — establishing the TCP handshake • TLS handshake — SSL/TLS negotiation (for HTTPS) • Request sent — uploading the request to the server • Waiting (TTFB) — time from request sent to first byte received; this is the server processing time
Where to find it in DevTools: Network panel → click any request → Timing tab → "Waiting (TTFB)"
Interpreting TTFB: • Under 200ms — good • 200ms–500ms — acceptable for dynamic pages • Over 500ms — investigate server-side bottleneck (slow DB query, no caching, cold start)
TTFB vs other timing vocabulary: • Content Download — time to download the response body after the first byte • FCP (First Contentful Paint) — when the browser renders any content from the DOM • LCP (Largest Contentful Paint) — when the largest element in the viewport renders • Stalled — time before the request could be sent (see question 5)
Common causes of high TTFB: • No CDN — origin server is geographically far from the user • Slow database queries on the server • No server-side caching (every request hitting the DB) • Serverless cold start latency
2 / 5
The Performance panel flags a "long task" with a red corner marker in the main thread timeline. What is a long task, and why is 50ms the threshold?
Long Task — Performance panel vocabulary:
A Long Task is a JavaScript task that occupies the browser's main thread for more than 50ms continuously. DevTools marks these with a red triangle in the Main thread flame chart.
Why the main thread matters: The browser's main thread handles JavaScript execution, style calculations, layout, painting, and compositing. When a long task runs, everything else is blocked — including responding to user input.
The RAIL model and 50ms: • Response — user input should be acknowledged within 100ms • 50ms = half of 100ms, leaving a budget for other browser work after the script finishes • If a task takes 200ms, the user experiences ~150ms of unresponsiveness
Total Blocking Time (TBT): The sum of the "blocking portion" of all long tasks (the milliseconds over 50ms). A Core Web Vital metric. Good: under 200ms.
Interaction to Next Paint (INP): Replaced FID in 2024. Measures the worst-case interaction delay. Long tasks are the primary cause of poor INP.
What causes long tasks: • Parsing and executing large JS bundles • Expensive React re-renders (reconciliation) • Synchronous XHR (rare but catastrophic) • Large DOM manipulation in a loop • JSON.parse on very large payloads on the main thread
How to fix: • Code-split large bundles • Yield to the browser with setTimeout(fn, 0) or scheduler.yield() • Move work to a Web Worker • Use requestIdleCallback for non-urgent work
3 / 5
A developer opens the Performance panel flame chart and asks: "What does the x-axis represent vs the y-axis?" How do you read a flame chart?
X-axis = Time Left-to-right is chronological. The ruler at the top shows milliseconds since the recording started. Each bar starts where the function was called and ends where it returned.
Y-axis = Call stack depth • Top row — the "root" caller (e.g., a click event handler, a timer callback) • Each row below — a function called by the row above • Bottom row — the deepest function actually doing the work (the "hot path")
Reading a flame chart: • Wide bars — the function took a long time (either doing work or waiting for callees) • Narrow bars — fast functions; usually not worth optimising • Tall stacks — deep call chains; not necessarily slow • Flat stacks — simple code paths
Types of flame chart in DevTools: • Main thread — JS execution, rendering pipeline tasks • Timings — LCP, FCP, user-defined performance.mark() markers • Network — waterfall of resource requests • GPU — compositing work
Vocabulary: • self time — time spent in the function itself (excluding callees) • total time — self time + time in all called functions • bottom-up view — aggregated by function, sorted by self time; shows which function consumed the most CPU • call tree — top-down hierarchical view of the call stack
4 / 5
A Memory panel heap snapshot shows a large object with retained size much larger than its shallow size. What is the difference between these two metrics?
Heap snapshot vocabulary — Memory panel:
Shallow size The memory allocated for the object's own primitive values and references (pointers). Does not include the memory of the objects it references. Example: an array of 1000 object references has a small shallow size (just the array structure + 1000 pointers), but each referenced object adds to retained size.
Retained size The amount of memory that would be freed if this object — and everything exclusively reachable through it — were garbage-collected. It answers: "How much memory does removing this object save?"
Retainers tree: DevTools shows a "Retainers" section for each object — the chain of references keeping the object alive (preventing GC). This is crucial for finding memory leaks: if a live root (window, DOM, closure) holds a reference to a large subgraph, that entire subgraph cannot be collected.
Common memory leak patterns: • Detached DOM nodes — DOM elements removed from the document but still referenced in JS variables • Closures capturing large objects — event listeners or callbacks holding references • Growing caches without eviction — Maps/Sets/arrays that only grow • Global variables — accidentally assigned without let/const
Vocabulary: • GC root — an entry point the garbage collector always considers live (window, current call stack) • heap snapshot — a point-in-time dump of all objects on the JS heap • allocation timeline — records objects as they are allocated over time • allocation sampling — low-overhead profiler that samples allocations by call stack
5 / 5
The Network panel shows several requests with significant time in the "Stalled" state before the actual request begins. What causes a request to be stalled?
"Stalled" (also called "Queued" in some DevTools versions) appears in the Timing tab as the very first phase — before DNS, TCP, or TLS. It means the browser is ready to make the request but something is blocking it from starting.
Causes of Stalled:
1. Connection limit (most common in HTTP/1.1) HTTP/1.1 browsers allow max 6 simultaneous TCP connections per origin. The 7th request must wait for one of the first 6 to finish. This causes the "waterfall staircase" pattern. Fix: use HTTP/2 (multiplexes all requests over one connection) or split resources across domains (domain sharding — less relevant with HTTP/2).
2. Higher-priority resources The browser prioritises render-blocking resources (HTML parser-blocking scripts, critical CSS) over lower-priority requests.
3. Allocating a socket If the browser is waiting to allocate a TCP connection from the pre-connect pool.
4. Disk cache check Some browsers briefly stall while checking whether the resource is in the disk cache.
Network panel vocabulary: • Queueing — same as Stalled; the request is in the browser's queue • Waterfall — the visual timeline of all network requests showing their phases • Connection ID — DevTools shows which TCP connection was reused (HTTP keep-alive / HTTP/2) • Priority — each resource has a priority (Highest, High, Medium, Low, Lowest) visible in the Network panel • Initiator — what triggered the request (HTML parser, script, fetch call, prefetch)