Web Performance
Web performance is where interviewers check whether you can reason about the whole delivery path rather than just write components. This tree covers framework-agnostic performance: Core Web Vitals, loading and critical-path strategy, bundle size, image/font strategy, runtime cost, delivery and caching, and how all of it is measured.
on this pageshowhide
explore
- Core Web Vitals23 questions
- Largest Contentful Paint (LCP)4 questions
- Interaction to Next Paint (INP)5 questions
- Cumulative Layout Shift (CLS)4 questions
- Supporting Metrics5 questions
- Thresholds and Scoring5 questions
- Loading and Critical Path31 questions
- Critical Rendering Path5 questions
- Script Loading Strategy5 questions
- Resource Hints6 questions
- Priority Hints and Fetch Priority4 questions
- Lazy Loading Strategy5 questions
- Streaming and Progressive Rendering6 questions
- Bundle Size and Code Splitting24 questions
- Splitting Strategy4 questions
- Bundle Analysis5 questions
- Bundle Budgets5 questions
- Tree Shaking and Dead Code4 questions
- Third-Party Script Cost6 questions
- Image and Font Strategy28 questions
- Modern Image Formats5 questions
- Responsive Image Strategy4 questions
- Image CDNs and Pipelines5 questions
- Font Loading and font-display5 questions
- Subsetting and Fallback Matching5 questions
- Media Impact on LCP and CLS4 questions
- Runtime Performance23 questions
- Long Tasks and the Main Thread5 questions
- Yielding and Scheduling Work4 questions
- Layout Thrashing4 questions
- Animation Performance Strategy5 questions
- Memory Leaks in SPAs5 questions
- Delivery and Caching19 questions
- Asset Caching Strategy4 questions
- CDN and Edge Delivery4 questions
- Service Worker Caching Strategy4 questions
- Back/Forward Cache4 questions
- Compression and Transport3 questions
- Measurement and Monitoring26 questions
- Lab vs Real-User Monitoring5 questions
- Browser Performance APIs6 questions
- Profiling Workflow5 questions
- Performance Budgets in CI5 questions
- Percentiles and Distributions5 questions
questions
174 · 7 sectionsWhat does the Cumulative Layout Shift (CLS) metric measure on a web page, and which kinds of on-screen movement does it deliberately not count?
basics
~20 sCLS scores how much visible content moves unexpectedly during a page's life. It ignores movement the user just triggered — shifts within 500 milliseconds of a click, tap or key press — and elements moved with CSS transforms.
On a web page, which user interactions does the Interaction to Next Paint (INP) metric measure, and which common ones does it ignore?
basics
~20 sINP measures discrete interactions — clicks, taps and key presses — timing each from the user's input to the next frame painted after the page responds. Scrolling and hovering are excluded, and one value per page visit is reported.
What does the Largest Contentful Paint (LCP) metric measure on a web page, and which elements are eligible to be reported as the LCP element?
basics
~20 sLCP records when the largest content element visible in the viewport finished rendering, timed from the start of navigation. Eligible candidates are images, SVG <image> elements, video poster frames, elements with a CSS background-image, and block-level elements containing text.
In web performance, what does First Contentful Paint (FCP) mark on a page load, what counts as "contentful" for it, and what does a good FCP still fail to tell you about the experience?
basics
~20 sFirst Contentful Paint marks the moment the browser first renders any piece of DOM content — text, an image, a non-white canvas or an SVG. It proves the page has stopped being blank, but says nothing about whether the main content or anything usable has arrived.
How is the score for a single layout shift calculated, and how are the individual shifts on a page combined into the reported Cumulative Layout Shift (CLS) value?
basics
~20 sEach shift scores impact fraction times distance fraction: the share of the viewport the moving content covered before and after, times how far it moved relative to the viewport's larger side. The page reports the largest sum inside one session window.
What is a web page's critical rendering path, and what does it mean for a resource to be render-blocking?
basics
~20 sThe critical rendering path is everything a browser must fetch and process before it can paint: the HTML, the DOM built from it, and the CSS. A render-blocking resource is one the browser insists on having before that first paint.
In web performance, what does deferring the download of a page's offscreen images and iframes until the user scrolls near them actually save, and what does it not make faster?
basics
~20 sDeferring offscreen images and iframes saves bytes, requests and connection capacity for content the user never scrolls to, leaving more bandwidth for what is on screen first. It does not make the deferred content itself arrive faster — it arrives later, on demand.
In an HTML page's head, what is the difference between <link rel="preload"> and <link rel="prefetch">, and which navigation does each one serve?
basics
~20 spreload fetches a resource the current page definitely needs, at high priority, during this navigation. prefetch fetches something a likely next navigation will need, at the lowest priority, using idle time. Same syntax, opposite intent.
In an HTML page, what is the difference between a parser-blocking resource and a render-blocking one, and why does a synchronous <script> placed after a <link rel="stylesheet"> wait for that stylesheet before it runs?
basics
~20 sParser-blocking stops the HTML parser from building more DOM; render-blocking only withholds the first paint while parsing continues. A synchronous script waits for preceding stylesheets because it may read computed styles, which requires a complete CSSOM.
Some teams apply lazy loading to every image, iframe and offscreen section on a page by default. What does that blanket policy cost, and how do you decide what is genuinely safe to defer?
basics
~20 sDeferring everything delays content the user is already looking at, so the page starts slower rather than faster. Draw the line by viewport probability: anything that paints in the first screen loads eagerly, and only content the user may never reach is deferred.
In a single-page app, route-based code splitting ships each route's JavaScript as a separate chunk fetched on navigation. What does that change about the first page load, and what does it not change about the total JavaScript a user who eventually visits every route downloads?
basics
~20 sRoute-based splitting shrinks the first download to the landing route's code, so the app becomes interactive sooner. It does not reduce total JavaScript: a user who visits every route still fetches all of it, just later and in more requests.
A product manager wants evidence before agreeing to drop an analytics vendor from your site. How would you measure what that one third-party script actually costs the page, in numbers rather than adjectives?
basics
~20 sAttribute cost per origin: count the requests and bytes that vendor's hosts pull, measure the main-thread time its scripts occupy, then block the domain and re-measure the same journey. The difference is the number to report.
In a bundled web app you add `import { debounce } from 'lodash'` for one small helper, and the production bundle grows by roughly 70 kB even though the build has tree shaking enabled. How do you work out why, and what are your options for getting those bytes back?
basics
~20 sTree shaking cannot narrow what the module format hides: lodash's main published build is CommonJS, so a named import still drags in the whole library. Confirm the size in the build output, then deep-import lodash/debounce, switch to lodash-es, or drop the dependency.
A frontend team writes its JavaScript bundle budget as "150 KB". Which measurement should that number refer to — the file on disk or the bytes on the wire — and why does the budget also have to name the compression algorithm?
basics
~20 sA transfer budget should be measured on the compressed bytes actually sent, not the file on disk, and it must name the algorithm: brotli output for the same JavaScript is typically noticeably smaller than gzip, so "150 KB" is ambiguous otherwise.
In a JavaScript bundle treemap report such as the one webpack-bundle-analyzer produces, what does the area of each rectangle represent, and what does the report not tell you about the code inside it?
basics
~20 sEach rectangle's area is the byte size that module contributes to an emitted chunk, nested by its folder path. The report shows what is in the bundle and how heavy it is — never whether that code ever runs.
In CSS, what does the font-display descriptor inside an @font-face rule control, and what is the difference between FOIT and FOUT?
basics
~20 sfont-display tells the browser what to paint while a web font is still downloading: nothing (FOIT, a flash of invisible text) or the fallback family (FOUT, a flash of unstyled text that is later replaced by the web font).
When choosing a file format for a page's images, how do you decide between JPEG, PNG and SVG for a photograph, a flat UI illustration, and a logo — and what does each choice cost in bytes?
basics
~20 sMatch the format to the content: JPEG for photographs, PNG when flat artwork needs exact pixels or transparency, SVG for vector art such as logos and icons that must stay crisp at any size and any screen density.
A page ships one 2000px-wide hero photo and lets CSS scale it down to fit whatever screen it lands on. Why is that a performance problem on a phone, and what does serving a set of widths instead actually save?
basics
~20 sThe browser downloads a 2000px image's full bytes no matter how small CSS draws it, so a phone that needs roughly 800 pixels of width pays for several times the pixels it can show. Serving a ladder of widths recovers that budget.
In a CSS @font-face rule, how do the font-display values block, swap, fallback and optional differ in terms of the block period and the swap period?
basics
~20 sEach value sets two windows. block gives a short blocking window then swaps whenever the font lands; swap blocks for almost nothing and swaps at any time; fallback blocks briefly and swaps only within a short window; optional blocks briefly and never swaps on that load.
For the same photograph, what do AVIF and WebP actually buy you over JPEG, and what are the tradeoffs that stop you from simply encoding everything as AVIF?
basics
~20 sBoth compress photographs far better than JPEG — WebP typically around a quarter to a third smaller, AVIF usually smaller again — and both support alpha. AVIF costs much more CPU to encode, can smear fine detail, and can inflate tiny flat images.
A designer asks for animations that stay smooth on a 60 Hz display and on a 120 Hz laptop. How much wall-clock time does one frame give you at each refresh rate, and why is the budget for your own work smaller than that number?
basics
~20 sA frame lasts about 16.7 ms at 60 Hz and about 8.3 ms at 120 Hz. The browser needs part of every frame for its own style, layout, paint and compositing work, so budget only around half of it — roughly 8-10 ms at 60 Hz — for your code.
A single-page app swaps views in and out without ever reloading the document. When a view is torn down, what must its setup code release so the view's memory can be reclaimed, and why does skipping that matter more here than on a traditional multi-page site?
basics
~20 sRelease everything setup registered on something longer-lived than the view: listeners on window or document, timers, observers, store and socket subscriptions, in-flight requests, and entries pushed into module-level collections. A multi-page site gets a clean heap on every navigation; an SPA never does.
In a Chrome DevTools performance recording, one JavaScript call in the flame chart sits above dozens of alternating short "Recalculate Style" and "Layout" entries, instead of a single layout at the end of the frame. What does that pattern tell you, and how do you get from it to the line of code responsible?
basics
~20 sThat sawtooth is layout thrashing: the code measures geometry and mutates the DOM in the same loop, so each iteration forces the browser to redo layout. To locate it, open the detail pane on one of those layout entries — DevTools flags a forced layout and links to the JavaScript that triggered it.
In web performance, what counts as a "long task" on the browser's main thread, why is the threshold 50 ms rather than a frame's 16 ms, and what does a single long task cost the user?
basics
~20 sA long task is one uninterrupted unit of main-thread work lasting over 50 ms. The 50 ms comes from the roughly 100 ms budget for responding to input: it leaves half that budget free. While a long task runs, input, timers and frames all wait.
On a web page, a button's click handler marks the row as selected in the DOM and then spends about 300 ms recalculating a summary, all in one synchronous block, and Interaction to Next Paint (INP) for that button is poor. Where in the handler do you introduce a yield back to the browser, and why does the placement matter more than how much work the handler does?
basics
~20 sYield right after the DOM update that shows feedback and before the expensive recalculation. The interaction is timed until the next paint, so painting the feedback first closes the measured window while the heavy work runs after it.
A production build emits `app.9f2c1a4b.js` instead of `app.js`. Why is that hash computed from the file's contents rather than from the release number or build id, and what caching policy does it unlock?
basics
~20 sA content hash changes only when the file's bytes change, so unchanged files keep their URL across releases and stay cached, while changed files get a new URL nobody has cached. That is what makes a year-long cache lifetime safe.
A site starts serving through a CDN. Explain the mechanism by which answering from an edge location near the user makes a request faster, and name one kind of request a CDN cannot speed up much.
basics
~20 sA CDN keeps copies of responses in data centres near users, so each request travels a short distance instead of crossing an ocean, removing most of the round trips before the first byte. It only helps responses it can cache; an uncacheable, per-user response still goes to the origin.
Your build produces a 380 kB JavaScript bundle, but the browser reports about 110 kB transferred for that file. What accounts for the gap, and how many bytes does the browser actually have to parse and execute?
basics
~20 sThe server compressed the response with gzip or Brotli, so only compressed bytes crossed the network. The browser decompresses first and then parses all 380 kB, so compression saves download time, not parse or execution cost.
A CDN dashboard reports a 55% cache hit ratio for a site's static assets. What does that number actually mean, and what are the usual reasons an edge cache misses on files that never change?
basics
~20 sCache hit ratio is the share of requests an edge answered from its own cache instead of fetching from the origin. On never-changing files a low ratio usually means cache-key fragmentation from query strings, a lifetime shorter than the gap between requests, traffic spread thinly across independent PoPs, or responses the CDN was told not to store.
On a shopping site, tapping the browser Back button from a product page to the results list is instant on some sites and looks like a full page load on others. What does the browser's back/forward cache change for the user, and why do performance teams treat that difference as worth chasing?
basics
~20 sA back/forward cache restore returns the previous page instantly — scroll position and in-page state intact, no network requests and no scripts re-run. Back navigations are a sizable share of real traffic, which makes eligibility one of the cheapest perceived-speed wins available.
What is a performance budget in a web project's CI pipeline, and what has to be true of it before it actually prevents regressions?
basics
~20 sA performance budget is a limit agreed in advance on a measurable property of the built site — bytes shipped, request count, or a metric such as LCP — that a CI job checks on every pull request and fails the build when exceeded.
In web performance work, what is the difference between lab (synthetic) data and field data (real-user monitoring), and what question is each one good at answering?
basics
~20 sLab data comes from a page load you generate yourself on a chosen device, network and cache profile, so it is repeatable and debuggable. Field data comes from real visitors' browsers, so it is messy but describes what users actually experienced.
A page scores in the high 90s in a local Lighthouse run, but the Core Web Vitals field data for the same page is failing. Explain how both can be true, and how you would reconcile them.
basics
~20 sA lab run measures one scripted load on a device, network and cache profile you chose; field data aggregates every real visit on real hardware. Both can be accurate because they describe different populations and, for some metrics, different definitions.
Core Web Vitals are assessed at the 75th percentile of visits rather than at the median or the 95th. What does "p75 LCP is 2.4 seconds" actually tell you about your users, and why is p75 the chosen cut point?
basics
~20 sA p75 LCP of 2.4 seconds means three quarters of measured page loads reached their largest contentful paint at or before 2.4 seconds, and one quarter were slower. p75 is chosen because it represents most visits while staying far enough from the extreme tail to be stable and actionable.
An analytics module creates a PerformanceObserver for the 'largest-contentful-paint' entry type, but on fast page loads its callback never fires. Which observe() option was most likely omitted, and what does that option do?
basics
~20 sThe observe() call omitted buffered: true. A PerformanceObserver normally only sees entries created after it registers, so an observer starting late misses events the browser already recorded. buffered: true replays matching entries already sitting in the performance timeline, and it only works with the single-type form of observe().