Part 5 · 3 chapters · ~35 min
Performance
Recording and its settings, the tracks in the order to read them (Frames, Interactions, Timings, Network, Main and its flame chart, the bottom pane), every pipeline event and the fields and warnings that explain its cost, and a table of patterns to recognise at a glance with where each fix lives.
15
Recording, and the tracks
recording
- Record (⌘E) captures from now; Record and reload captures a page load from navigation to a few seconds after load. Stop when the symptom has happened. Keep recordings short: a 10 s trace is readable, a 60 s one is a haystack.
- Settings (the gear): CPU throttling (4× or 6× to make a laptop behave like a phone), network throttling, Screenshots (on, always), Memory (adds a heap and nodes graph), Web Vitals, Selector Stats (for style investigations), "Disable JavaScript samples" (lighter trace, no flame chart: rarely).
- Save and load: the download icon exports JSON; load someone else's trace with the upload icon. The trace is the artefact you attach to a bug or a PR.
the tracks, and the order to read them
- Overview: CPU by category, network, screenshots; drag to zoom.
- Frames: green on time, yellow partial, red dropped. The red run is where the user felt it.
- Interactions: each input as a bar with whiskers: input delay, processing, presentation delay. The longest is the INP candidate.
- Timings: FCP, LCP (linked to the element), DCL, L, and your
performance.mark/measurespans. - Network: requests aligned with Main; a gap in Main under a request bar is waiting.
- Main: a bar per task, the flame chart beneath; long tasks carry a red triangle. Other threads (compositor, raster, workers) and GPU collapsed below.
- Bottom pane for the selection: Summary (pie by category), Bottom-Up (self time per function: the hot function regardless of caller), Call Tree (top-down: the entry point), Event Log.
the reading order
Symptom in Frames or Interactions → zoom → the task on Main under it → the widest child in the flame chart → Bottom-Up by self time for the function → Summary for the category. Then one sentence: what ran, how long, what it forced, what it painted.
THE PERFORMANCE PANEL, TRACK BY TRACK
what each lane of a recording shows, and the order to read them in
swipe the figure sideways, or tap expand for full screen
1/6
overview
The overview at the top: CPU usage coloured by category (yellow script, purple style and layout, green paint, grey other), network as thin bars, and the screenshots strip (enable "Screenshots"). Drag across it to zoom the tracks below to that range; the Frames and Interactions tracks are the first place to look for the symptom.
16
The events, and what each one means
by stage
- Parse HTML (blue): the parser running; a long one is a big document or a parser-blocking script between chunks.
- Evaluate Script, Compile Code, function calls (yellow): the task's origin (Timer Fired, Event: click, Animation Frame Fired, XHR Load, Run Microtasks) and what it did.
(anonymous)hides the rest: name your functions. Minor GC / Major GC (grey) under allocation-heavy loops is the JS course part 5's allocation pressure. - Recalculate Style (purple): Summary shows "Elements affected"; with Selector Stats, a table of selectors by elapsed time and match attempts. Thousands affected from a class on body is the theme-toggle shape; thousands of attempts with few matches is an expensive selector.
- Layout (purple): "Nodes that need layout", the root, and ⚠ Forced reflow when a read forced it mid-script; the warning links to the read. A comb of small Layouts in one task is thrashing; one at the end of the task is the normal frame.
- Pre-Paint, Paint (green): the layer and area painted; many per frame or large area for a small change is the repaint pathology. Rasterize Paint on raster threads; Composite Layers cheap unless layers explode.
warnings and insights
- The red triangle (long task over 50 ms); ⚠ on forced reflows; "Handler took N ms" on input events; the Insights sidebar (LCP breakdown, render-blocking requests, layout shift culprits, forced reflows, third-party cost) with links into the trace. Read them after reading the task, not instead.
go to the lab
/layout/thrashwith 4× CPU: record the write-read loop. Find the comb of Layout events under the click task, each with ⚠; click one warning to land on theoffsetWidthread. Record the batched version: one Layout at the end./style/theme-toggle: enable Selector Stats, record the toggle, select the Recalculate Style event, read Elements affected and the selector table./loop/long-task: record both buttons. Compare the Interactions bars and read Bottom-Up for the whole-task version:busyat the top by self time./perf/inp-phases: record a click with all three toggles on; hover the interaction bar for the three phases; then fix one toggle at a time and record again, three times. Write the four numbers./paint/hover-shadow: record a hover across the cards; count Paint events per frame and read the painted area; enable the fix and record again./paint/transform-vs-left: record five seconds; the Main thread shows Layout and Paint every frame for the top box and nothing for the bottom one; the Compositor thread shows frames for both.
THE EVENTS AND WHAT EACH MEANS
Recalculate Style, Layout, Pre-Paint, Paint, Composite, and the warnings attached to them
swipe the figure sideways, or tap expand for full screen
1/6
Recalculate Style
Recalculate Style: the Summary shows "Elements affected" and, with Selector Stats enabled in the panel settings, a table of selectors by elapsed time and match attempts. 4,000 elements affected from a class toggle on body is the theme-toggle pathology; a selector with thousands of match attempts and few matches is the right-to-left matching cost from the Browser course part 3.
17
Patterns to recognise at a glance
| what you see | what it is | where the fix lives |
|---|---|---|
| One wide yellow task with a red triangle after a click | Synchronous work in a handler (the INP processing phase) | FSD M2: a worker, chunking, or less work; React part 5 for transitions |
| Many narrow yellow tasks, one per message, frames dropping | A render per event (live data) | FSD M4 and M8: coalesce into frames |
| A comb of purple Layout events inside one task, each ⚠ | Layout thrashing: write, read, write, read | Browser part 4: batch reads before writes |
| One large purple Recalculate Style with thousands affected | A broad invalidation (a class high in the tree, or a descendant selector) | Browser part 3: scope the selector; custom properties for themes |
| Green Paint every frame during a hover or animation | A property that repaints (shadow, left, top, width) | Browser part 5: transform and opacity; promote what moves |
| Frames red while Main is idle; Compositor busy | Too many layers, or raster-bound (huge images, large layers) | Layers panel (part 8); fewer and smaller layers; sized images |
| A gap in Main with a Network bar above it | Waiting for a request; nothing to fix in script | Part 4: priorities, TTFB, preconnect |
| Grey GC blocks every few ms inside a loop | Allocation pressure | JS part 5 and 14: allocate outside the loop; typed arrays |
| Long Parse HTML with a yellow Evaluate Script in the middle | A parser-blocking script | Browser part 2: defer, async, move to the end |
| A task that is wide but mostly idle (no children) | Waiting on a synchronous API (alert, sync XHR, a huge localStorage read) | Storage lab: localstorage-cost; remove sync APIs |
| Interactions bar with a long left whisker | Input delay: the thread was busy when the input arrived | Find the task that was running; it is the real culprit |
| LCP marker late, with the image request starting late | Resource load delay: discovered late (CSS background, JS-inserted) | Browser part 12: preload, fetchpriority, in the HTML |
the discipline
A trace is evidence; the table is a vocabulary. Name the pattern, record the number, apply the one fix the pattern implies, record again. Part 10 runs this on five whole diagnoses.