Skip to content

Chapter 7 of 8

Runtime Performance and Responsiveness

Once the page is loaded, the metric that matters is INP, which captures how long users wait between an interaction and the visible response. INP is bottlenecked by main-thread work, because the same thread parses HTML, runs JavaScript, computes style and layout, paints pixels, and dispatches events. A long task is any JavaScript work that blocks the main thread for more than 50 milliseconds, and every long task during a user interaction extends INP. The Long Animation Frames API captures frames where scripting plus style plus layout plus paint exceed a threshold, giving an even richer signal than long tasks alone. PerformanceObserver exposes long tasks, paint timings, and layout shifts from JavaScript so teams can monitor them in their own analytics.

Three patterns break up blocking work: yield to the browser, run work off-thread, and defer non-urgent updates. The scheduler API provides scheduler.postTask with explicit priorities and scheduler.yield() to voluntarily return control so pending input events can be processed mid-task. Web Workers run JavaScript on a background thread, with Comlink wrapping the postMessage protocol in a promise-based API to make heavy computations feel like normal async calls. requestIdleCallback schedules low-priority work during browser idle periods, while requestAnimationFrame synchronizes visual updates with the repaint cycle and is the right hook for any animation that touches the DOM.

Layout thrashing is a common source of forced synchronous layout: when code writes to styles and then immediately reads layout properties such as offsetWidth or scrollTop, the browser must compute layout to return a value, costing much more than either operation alone. Batching all reads before all writes eliminates this, as does moving measurements into animation frames. The DevTools performance tab exposes these patterns in the main-thread flame chart and identifies which scripts and styles triggered layout, and the will-change CSS hint promotes a layer in advance but should be used sparingly because promoting too many layers hurts memory and paint cost.

Framework-specific tools amplify these primitives. React.memo skips re-rendering when props are referentially equal and is useful for expensive leaves. useDeferredValue marks non-urgent updates so urgent input stays snappy, and useTransition signals that an update may be deferred while the previous UI remains interactive. Automatic batching in React 18 and later consolidates state updates inside event handlers, promises, and timeouts into a single render, removing the need for setTimeout(0) tricks that older code used to escape batching. useLayoutEffect runs synchronously before paint and should be reserved for cases where useEffect would cause visible flicker, since heavy synchronous work there blocks the very update it is meant to support. The general pipeline summary is JavaScript to style to layout to paint to composite, and animations that touch only transform and opacity are compositor-friendly because they skip layout and paint entirely.

All chapters
  1. 1Foundations of Frontend Performance
  2. 2The Critical Rendering Path and Resource Loading
  3. 3Network, Compression, and Delivery
  4. 4Images, Fonts, and Media
  5. 5JavaScript Bundle Optimization
  6. 6CSS Performance
  7. 7Runtime Performance and Responsiveness
  8. 8Rendering Architecture, Tooling, and Long-Term Strategy

Drill it

Reading is not remembering. These come from the Frontend Performance deck:

Q

What is frontend performance?

Frontend performance is how quickly and smoothly a web application loads, renders, and responds to user input.

Q

Why does frontend performance matter?

It affects user satisfaction, accessibility, SEO, conversion, and perceived product quality.

Q

What is Time to First Byte (TTFB)?

TTFB measures how long it takes the browser to receive the first byte of the response after making a request.

Q

What is Largest Contentful Paint (LCP)?

LCP measures when the largest visible content element finishes rendering, indicating perceived load speed.