Web Performance · Part 22 — Capstone 2: Systematic Performance Investigation
Ghép mọi phần chuyên sâu thành khung chẩn đoán triệu chứng → metric → công cụ → cách sửa, từ field data tới nguyên nhân gốc xuyên mọi tầng.
Phần 12 dạy quy trình audit + budget. Capstone thứ hai này dạy kỹ năng cao hơn: điều tra — khi field data báo một metric xấu, làm sao truy ngược tới đúng nguyên nhân giữa hàng chục khả năng, rồi chọn đúng cách sửa. Đây là điểm hội tụ của cả loạt bài chuyên sâu 13–21, đóng gói thành một khung quyết định lặp lại.
Khác audit (quét rộng tìm mọi vấn đề), điều tra là truy sâu một triệu chứng cụ thể tới root cause. Cả hai cần thiết; phần này về cái thứ hai.
1. Vòng lặp điều tra
① ĐO (field) RUM/CrUX cho thấy metric nào xấu, ở đâu (route/thiết bị/mạng)
② PHÂN RÃ dùng Attribution để chẻ metric thành các giai đoạn
③ TÁI HIỆN (lab) reproduce trong DevTools với throttle giống phân khúc xấu
④ TÌM GỐC dùng đúng công cụ cho giai đoạn nghi ngờ
⑤ SỬA 1 THỨ đổi đúng một biến số
⑥ ĐO LẠI xác nhận ở lab, rồi theo dõi field sau deploy
⑦ LẶP / chốt budget
Nguyên tắc xuyên suốt cả series: đo trước, sửa sau; field cho biết kết quả người dùng, lab giúp chẩn đoán cơ chế; sửa một thứ một lúc để biết cái gì có tác dụng. Field cũng có sampling bias/độ trễ, nên luôn đọc coverage và sample count.
2. Bản đồ triệu chứng → metric → công cụ → cách sửa
Đây là trái tim của capstone: khung tra cứu nối mọi phần.
LCP cao (nội dung chính hiện chậm)
Đo: LCP Attribution → TTFB? resource load delay/duration? element render delay?
Công cụ: WebPageTest waterfall, Lighthouse, RUM Attribution
Sửa: TTFB → SSR/edge/cache (Part 15,19); load → discover ảnh LCP sớm trong HTML,
dùng fetchpriority và chỉ preload khi resource bị phát hiện trễ (Part 14);
render delay → giảm JS chặn, hydration (Part 15,16)
INP cao (bấm/gõ phản hồi chậm)
Đo: INP Attribution → inputDelay? processing? presentation?
Công cụ: LoAF/Attribution khi browser hỗ trợ, Performance panel để tái hiện
Sửa: inputDelay → chia task + yield (Part 16); processing → tối ưu/worker (Part 16);
presentation → giảm reflow/DOM (Part 17); third-party? (Part 20)
CLS cao (layout nhảy)
Đo: CLS Attribution → largestShiftTarget
Công cụ: Performance panel (Layout Shift regions), DevTools
Sửa: đặt kích thước ảnh/embed, reserve space, tránh chèn trên (Part 7);
font swap (Part 10); streaming cần đặt chỗ trước (Part 15)
TTFB cao (server chậm trả byte đầu)
Công cụ: Server-Timing, Navigation/Resource Timing, WebPageTest
Sửa: cache/CDN/edge (Part 19), SSG/ISR (Part 15), tối ưu backend/query
Bundle phình / tải chậm
Công cụ: treemap, size-limit (Part 21)
Sửa: code-split, tree-shake, thay dep nặng, lazy (Part 8,21)
App chậm dần theo thời gian
Công cụ: heap snapshot, Performance memory (Part 18)
Sửa: gỡ listener/timer, fix detached DOM (Part 18)
3. Tái hiện đúng điều kiện
Lỗi field thường không tái hiện trên MacBook cắm điện. Phải mô phỏng phân khúc xấu (từ bước ② phân khúc RUM):
DevTools cài đặt tái hiện:
- CPU throttling được hiệu chỉnh theo máy chạy; 4x–6x chỉ là điểm bắt đầu
- Network: Slow 4G
- cache: disabled (first visit) hoặc enabled (repeat) tùy kịch bản đo
- device emulation đúng viewport
- thử cả cold start và sau nhiều tương tác (cho INP/memory)
Nếu field nói “mobile p75 INP = 600ms” mà lab không tái hiện, có thể throttle chưa sát, user flow khác, thiết bị/memory khác, third-party/A-B test khác hoặc sample field gồm trạng thái app bạn chưa dựng lại. Ưu tiên test trên thiết bị đại diện; throttle desktop chỉ là mô hình, không phải bản sao điện thoại.
4. Một ca điều tra mẫu (end-to-end)
Triệu chứng: Search Console báo INP "Poor" trên route /products (mobile)
① ĐO: RUM cho thấy INP p75 = 550ms, chỉ mobile, chỉ /products
② PHÂN RÃ: Attribution → processingDuration chiếm 400ms; target = nút "Add filter"
③ TÁI HIỆN: CPU throttle đã hiệu chỉnh (~4x ở máy test) + Slow 4G → click filter mất ~500ms
④ TÌM GỐC: LoAF → script app.js, hàm applyFilters() chạy 380ms (lọc + re-render cả list)
⑤ SỬA: chia applyFilters thành chunk + scheduler.yield (Part 16);
thêm content-visibility cho list item (Part 17)
⑥ ĐO LẠI: lab → click ~120ms; deploy → field p75 INP /products mobile xuống 180ms ✅
⑦ CHỐT: thêm RUM alert/budget INP cho route + lấy mẫu LoAF diagnostic (Part 21)
Lưu ý cách điều tra đi thẳng tới nguyên nhân nhờ phân rã + công cụ đúng, thay vì đoán mò “chắc do bundle to”.
5. Các bẫy điều tra thường gặp
❌ Tối ưu cái dễ đo thay vì cái quan trọng (lab score thay vì field INP)
❌ Sửa nhiều thứ cùng lúc → không biết cái nào có tác dụng
❌ Tin "trực giác" về bottleneck thay vì đo (thường sai)
❌ Bỏ qua đuôi (p95/p99) — một nhóm nhỏ khổ sở vẫn là vấn đề
❌ Coi một mức throttle trên máy dev là bản sao mọi thiết bị thật
❌ Sửa xong không theo dõi field → hồi quy âm thầm quay lại
6. Toàn series — bản đồ Web Performance
NỀN TẢNG (1–12)
1 Tư duy & RAIL 7 Tối ưu CLS
2 Core Web Vitals 8 JS performance & bundle
3 Công cụ đo 9 Ảnh & media
4 Critical rendering path 10 Fonts
5 Tối ưu LCP 11 Network & caching
6 Tối ưu INP 12 Capstone 1 — audit & budget
CHUYÊN SÂU (13–22)
13 RUM & field data 18 Memory & phiên dài
14 Resource hints/Early Hints 19 Network protocol (HTTP/3)
15 Rendering & delivery 20 Third-party scripts
16 INP & scheduling (LoAF) 21 Budgets & culture at scale
17 Rendering pipeline/CSS 22 Capstone 2 — điều tra (bài này)
7. Tóm tắt
- Điều tra = truy sâu một triệu chứng tới root cause; vòng lặp: đo field kèm coverage/sample count → phân rã → tái hiện lab/thiết bị thật → tìm gốc → sửa một thứ → đo lại → chốt budget.
- Dùng bản đồ triệu chứng → metric → công cụ → cách sửa để đi thẳng tới nguyên nhân thay vì đoán: mỗi Core Web Vital có giai đoạn phân rã và bộ công cụ riêng.
- Tái hiện đúng điều kiện (thiết bị đại diện, throttle đã hiệu chỉnh, cold/warm, đúng user flow/variant) — lỗi field hiếm khi hiện nguyên dạng trên máy dev mạnh.
- Tránh bẫy: tối ưu cái dễ đo thay vì cái quan trọng, sửa nhiều thứ cùng lúc, tin trực giác, bỏ đuôi p95/p99, không theo dõi field sau sửa.
- Đây là điểm hội tụ của cả series: biến hiệu năng từ đoán mò thành chẩn đoán có hệ thống, neo vào field data và đóng vòng bằng budget + monitoring.
Cảm ơn bạn đã đi hết hành trình Web Performance & Core Web Vitals. Từ RAIL ở Phần 1 tới khung điều tra ở đây, thông điệp không đổi: đo trước, sửa cái lớn nhất, xác nhận bằng field data, và đặt guardrails để thành quả không trôi.