The Performance Golden Rule
"Send less data, less often, from nearby, when it is needed."
CSE 135 — Full Overview
Speed is not a feature. Speed is the baseline expectation.
The data is in and it is irrefutable:
The ancient Greeks distinguished two concepts of time:
A minute waiting for a page to load feels longer than a minute reading interesting content.
The expectation floor only moves in one direction: bank lines → pneumatic tubes → ATMs → card swipe → phone tap. Once users experience faster, they cannot un-experience it.
The user's total time: unlock device → open browser → type query → DNS → TCP → then your server sees a byte.
Three phases of the user journey:
Latency is the real enemy.
Data capacity per unit time. Diameter of the pipe.
A wider pipe carries more water — but doesn't make a drop arrive sooner.
Network delay / travel time. Length of the pipe.
Includes processing, queuing, and transmission delays at every hop.
| Term | Definition |
|---|---|
| TTFB | Time to First Byte — request sent to first byte arriving |
| TTLB | Time to Last Byte — request sent to final byte arriving |
| FCP | First Contentful Paint — first DOM content rendered |
| TTI | Time to Interactive — visually rendered AND responsive to input |
| LCP | Largest Contentful Paint — largest visible element rendered (Core Web Vital) |
| CLS | Cumulative Layout Shift — visual stability (Core Web Vital) |
| INP | Interaction to Next Paint — responsiveness to interactions (Core Web Vital) |
Response < 100ms. Animation < 10ms. Idle < 50ms. Load < 1s.
| Phase | Budget | What It Means |
|---|---|---|
| Response | < 100ms | Tap/click to visible feedback must feel instant |
| Animation | ~10ms/frame | 60 fps = ~16.66ms/frame. ~10ms of work to leave room for rendering. Failure = jank |
| Idle | 0–50ms | Background work in ≤ 50ms chunks. You share the main thread with the UI! |
| Load | < 1000ms | Critical above-the-fold content on screen. Avoid the White Screen of Death |
Start with client-side optimizations. They are simpler, easier to measure, and affect the largest portion of the user's experience. Client-side truly is harder than server-side.
The fastest byte is the one you never send.
The first question: do we really need this object?
The "localhost" effect: the developer's perception of performance isn't the user's reality on a slow phone over cellular.
<meta> tags that add no user-facing valueImporting all of Bootstrap CSS just to center a few elements. Including an entire JS library for one utility function. The entire framework ships to every user, every time.
<link> tag = high DX (easy for devs)"Code for maintenance, but prepare for delivery."
Minify first, then compress. They address different things and compound: minification removes structural redundancy, compression removes statistical redundancy.
| Technique | Example |
|---|---|
| Whitespace removal | Collapse multiple spaces (preserve <pre>, <textarea>) |
| Optional quote removal | <p id="foo"> → <p id=foo> |
| Comment removal | Strip <!-- --> (also reduces info leakage) |
| Boolean shortening | <hr noshade="noshade"> → <hr noshade> |
| Self-closing cleanup | <br /> → <br> |
| Entity remapping | ® → ® (whichever shorter) |
The final product is HTML — it is the atoms of web content. As the root document that triggers all other fetches, any delay adds delays to everything downstream.
CSS impact isn't just delivery — it's render blocking.
| Technique | Example |
|---|---|
| Unused CSS removal | PurifyCSS, PurgeCSS |
| Rule shorthands | margin-left/right/top/bottom → margin |
| Value recasting | #ff0000 → red, bold → 700 |
| Unit elimination | 0px → 0 |
| Rule merging | Collapse redundant selectors |
Extract above-the-fold CSS and inline it in <head>. Eliminates a render-blocking request for the initial viewport. Load full stylesheet asynchronously afterward.
JS abuse is arguably the worst performance issue on the modern web.
JavaScript must be downloaded, parsed, and compiled. It's a triple cost.
| Technique | Savings |
|---|---|
Variable name rewriting (var myLongName → var x) | Significant |
| Dead code elimination | Variable — can be very large in frameworks |
| Whitespace reduction | Moderate (watch for ASI) |
| Repetition rewrites | Moderate |
Code optimizations (i=i+1 → i++) | Small, adds up |
Fine polish for large-scale optimization.
Only rewrite dependent resource paths — user-facing URLs stay readable.
Up to 70% savings — usually just a server config change.
| Format | Notes |
|---|---|
| gzip | Universal support. The safe default. |
| Brotli | Better ratios. Requires HTTPS. Increasingly supported. |
| Deflate | Older. Largely superseded by gzip. |
| Dictionary | Emerging. Leverages "sameness" across web pages. |
Images are the biggest and most obvious byte savings opportunity — yet consistently neglected.
"Why do you keep sending me that logo?!" — Your browser
| Directive | Meaning | Use Case |
|---|---|---|
public | Any cache can store | Static assets |
private | Browser only | Personalized content |
max-age=N | Fresh for N seconds | 31536000 (1 year) for versioned assets |
no-cache | Revalidate before use | Changeable content |
no-store | Don't cache at all | Sensitive data |
immutable | Never changes | Content-hashed assets |
max-age — browser doesn't ask at all until expiredETag + If-None-Match → 304 Not Modified (no body)URL = cache key. To invalidate, change the URL:
app.3f2a1b.js (best practice)logo-v2.giflogo.jpg?ts=324243 (quick & dirty)One URL, multiple versions (compressed/uncompressed, WebP/JPEG, en/es). Vary tells caches which headers create distinct versions. Key becomes URL + Vary header.
Browser → Proxy → CDN edge → Reverse proxy at origin
Move content closer to users.
wwwamazon.com)Send the bytes when you need them — no earlier, no later.
Very little work for potentially quite a lot of gain:
| Hint | Purpose | When |
|---|---|---|
| preload | Fetch resource needed for current page but discovered late | Critical fonts, hero images |
| prefetch | Fetch resource likely needed for next navigation | Next-page assets |
| preconnect | Establish TCP+TLS early | CDN, analytics, font origins |
| dns-prefetch | Resolve DNS only (lighter) | Domains you might need |
<img src="photo.jpg" loading="lazy" alt="Below the fold"> <img src="hero.jpg" loading="eager" alt="Hero image">
Native standard — no JavaScript needed. If browsers support it, go native.
Don't send a monolithic bundle. Split by route — homepage gets homepage.js, checkout gets checkout.js.
Make the network a controlled — and even optional — component.
| Strategy | How It Works | Best For |
|---|---|---|
| Cache-first | Serve from cache; fetch on miss | Static assets (CSS, JS, images) |
| Network-first | Try network; fall back to cache | Dynamic content, APIs |
| Stale-while-revalidate | Serve stale immediately; update in background | Feeds, dashboards |
Performance optimization without measurement is guessing.
| Metric | What It Measures | Target |
|---|---|---|
| LCP | Largest visible element renders | ≤ 2.5s |
| INP | Responsiveness to interactions | ≤ 200ms |
| CLS | Visual stability | ≤ 0.1 |
| TTFB | Server + network responsiveness | ≤ 800ms |
| FCP | First visible content | ≤ 1.8s |
| TTI | Reliably interactive | ≤ 3.8s |
Perceived speed and actual speed are different things.
Keep people busy and occupied — from waiters bringing drinks early to Disneyland engaging you in a long line. The web has its own techniques:
private / no-store"Send less data, less often, from nearby, when it is needed."
| Concept | Key Takeaway |
|---|---|
| Why It Matters | Speed is the baseline expectation. Users abandon slow sites. Developer perceptions lie. |
| Bandwidth vs. Latency | Latency is the real enemy. Scale ≠ Speed. |
| RAIL | R < 100ms, A < 10ms, I < 50ms, L < 1s. ~90% is client-side. |
| Content Selection | Fastest byte = one you never send. JS costs far more than images. |
| Minification | Code for maintenance, prepare for delivery. Minify first, then compress. |
| Compression | gzip/Brotli: up to 70% savings. Server config, not code change. |
| Caching | Zero-latency for cached resources. Versioned filenames + long max-age. |
| CDNs & DNS | Move content closer. DNS optimization prevents bottlenecks. |
| Loading Strategy | Preload now, prefetch next, lazy-load below fold. HTTP/2 changes the calculus. |
| Service Workers | Make the network optional. Cache-first / network-first / stale-while-revalidate. |
| Monitoring | RUM reveals reality. Core Web Vitals. RAIL is a spectrum, not binary. |
| Interface Illusion | Perceived ≠ actual speed. Skeleton screens and optimistic UI are legitimate tools. |