Quá trình render trong trình duyệt
Để tối ưu hóa hiệu suất frontend một cách hiệu quả, chúng ta cần hiểu rõ cách trình duyệt thực sự xử lý và hiển thị nội dung web. Quá trình này, được gọi là Critical Rendering Path (CRP), là chuỗi các bước mà trình duyệt phải thực hiện để chuyển đổi HTML, CSS và JavaScript thành các pixel trên màn hình.
Quy trình render cơ bản của trình duyệt (Critical Rendering Path)
Critical Rendering Path bao gồm 5 bước chính:
flowchart TD
A[HTML] -->|Parse| B[DOM]
C[CSS] -->|Parse| D[CSSOM]
B --> E[Render Tree]
D --> E
E --> F[Layout]
F --> G[Paint]
G --> H[Composite]
H --> I[Display]
J[JavaScript] -->|Can modify| B
J -->|Can modify| D
style A fill:#f9d4d4,stroke:#c80505
style B fill:#d4f9d4,stroke:#05c805
style C fill:#d4d4f9,stroke:#0505c8
style D fill:#d4d4f9,stroke:#0505c8
style E fill:#f9f9d4,stroke:#c8c805
style F fill:#f9d4f9,stroke:#c805c8
style G fill:#d4f9f9,stroke:#05c8c8
style H fill:#f9d4d4,stroke:#c80505
style I fill:#d4f9d4,stroke:#05c805
style J fill:#f9d4d4,stroke:#c80505
1. Phân tích DOM và CSSOM
Khi trình duyệt nhận được phản hồi HTML từ server, nó bắt đầu phân tích mã HTML và chuyển đổi thành Document Object Model (DOM). DOM là một cấu trúc cây biểu diễn tất cả nội dung của trang.
flowchart LR
A[HTML] -->|"Parse"| B[Tokens]
B -->|"Tokenize"| C[Nodes]
C -->|"Build"| D[DOM Tree]
style A fill:#f9d4d4,stroke:#c80505
style B fill:#d4f9d4,stroke:#05c805
style C fill:#d4d4f9,stroke:#0505c8
style D fill:#f9f9d4,stroke:#c8c805
Đồng thời, trình duyệt cũng phân tích CSS để tạo CSS Object Model (CSSOM), một cấu trúc cây tương tự biểu diễn tất cả các quy tắc kiểu.
flowchart LR
A[CSS] -->|"Parse"| B[Tokens]
B -->|"Tokenize"| C[Nodes]
C -->|"Build"| D[CSSOM Tree]
style A fill:#d4d4f9,stroke:#0505c8
style B fill:#d4f9d4,stroke:#05c805
style C fill:#f9d4d4,stroke:#c80505
style D fill:#f9f9d4,stroke:#c8c805
Điểm quan trọng: Cả DOM và CSSOM đều là các cấu trúc cây độc lập. DOM chứa thông tin về cấu trúc nội dung, trong khi CSSOM chứa thông tin về cách định dạng nội dung đó.
2. Tạo Render Tree
Sau khi có DOM và CSSOM, trình duyệt kết hợp chúng để tạo Render Tree. Render Tree chỉ chứa các node cần thiết để hiển thị trang.
flowchart LR
A[DOM Tree] --> C[Render Tree]
B[CSSOM Tree] --> C
style A fill:#f9f9d4,stroke:#c8c805
style B fill:#f9f9d4,stroke:#c8c805
style C fill:#d4f9d4,stroke:#05c805
Render Tree không bao gồm các phần tử không hiển thị như:
- Các phần tử có
display: none
- Các phần tử script, meta, v.v.
- Các phần tử bị ẩn thông qua CSS
Điểm quan trọng: Render Tree là cơ sở cho các bước tiếp theo trong quá trình render. Nó chỉ chứa thông tin về những gì sẽ thực sự được hiển thị trên màn hình.
3. Layout (Reflow)
Trong bước này, trình duyệt tính toán vị trí và kích thước chính xác của mỗi phần tử trong Render Tree. Quá trình này còn được gọi là “reflow”.
flowchart LR
A[Render Tree] -->|"Calculate positions"| B[Layout]
B -->|"x, y, width, height"| C["Positioned Elements"]
style A fill:#d4f9d4,stroke:#05c805
style B fill:#f9d4f9,stroke:#c805c8
style C fill:#d4d4f9,stroke:#0505c8
Layout tính toán:
- Vị trí chính xác (tọa độ x, y)
- Kích thước (chiều rộng, chiều cao)
- Các mối quan hệ không gian giữa các phần tử
Điểm quan trọng: Bất kỳ thay đổi nào ảnh hưởng đến bố cục (như thay đổi chiều rộng, chiều cao, hoặc vị trí) đều sẽ kích hoạt lại quá trình layout, điều này có thể tốn kém về mặt hiệu suất.
4. Paint
Sau khi có thông tin bố cục, trình duyệt chuyển sang giai đoạn “paint”, nơi nó điền các pixel thực tế cho mỗi phần tử. Quá trình này bao gồm việc vẽ văn bản, màu sắc, hình ảnh, đường viền, bóng đổ, v.v.
flowchart LR
A[Layout] -->|"Draw pixels"| B[Paint]
B -->|"Colors, images, text"| C["Painted Layers"]
style A fill:#f9d4f9,stroke:#c805c8
style B fill:#d4f9f9,stroke:#05c8c8
style C fill:#f9f9d4,stroke:#c8c805
Paint thường diễn ra trên nhiều lớp (layers):
Điểm quan trọng: Paint là quá trình tốn kém nhất trong CRP. Các thuộc tính như shadows, gradients, và transforms có thể làm tăng đáng kể thời gian paint.
5. Composite
Trong bước cuối cùng, trình duyệt kết hợp các lớp đã được vẽ để tạo ra hình ảnh cuối cùng mà người dùng nhìn thấy.
flowchart LR
A[Paint] -->|"Combine layers"| B[Composite]
B -->|"Final rendering"| C["Screen Display"]
style A fill:#d4f9f9,stroke:#05c8c8
style B fill:#f9d4d4,stroke:#c80505
style C fill:#d4f9d4,stroke:#05c805
Compositing trở nên đặc biệt quan trọng khi có nhiều lớp chồng lên nhau hoặc khi có các hiệu ứng như transform 3D.
Điểm quan trọng: Các thuộc tính như transform
và opacity
có thể được tối ưu hóa để chỉ ảnh hưởng đến quá trình composite mà không kích hoạt lại layout hoặc paint.
Ảnh hưởng của JavaScript
JavaScript có thể ảnh hưởng đáng kể đến Critical Rendering Path:
Chặn parser: JavaScript mặc định là “parser-blocking”, nghĩa là khi trình duyệt gặp thẻ script, nó sẽ dừng việc phân tích HTML cho đến khi JavaScript được tải và thực thi xong.
Thay đổi DOM và CSSOM: JavaScript có thể thay đổi cả DOM và CSSOM, dẫn đến việc phải tính toán lại Render Tree, Layout và Paint.
Thời gian thực thi: JavaScript phức tạp có thể chiếm main thread trong thời gian dài, làm chậm quá trình render.
Giải pháp:
- Sử dụng
async
hoặcdefer
cho các script không cần thiết ngay lập tức - Tối ưu hóa thời gian thực thi JavaScript
- Chia nhỏ các tác vụ JavaScript dài
Các chỉ số hiệu suất quan trọng (Core Web Vitals)
Google đã giới thiệu Core Web Vitals như một tập hợp các chỉ số hiệu suất quan trọng nhất ảnh hưởng đến trải nghiệm người dùng.
flowchart LR
subgraph "Core Web Vitals"
A[LCP: Largest Contentful Paint] --> D["< 2.5s: Tốt"]
A --> E["2.5s - 4s: Cần cải thiện"]
A --> F["> 4s: Kém"]
B[FID/INP: First Input Delay] --> G["< 100ms: Tốt"]
B --> H["100ms - 300ms: Cần cải thiện"]
B --> I["> 300ms: Kém"]
C[CLS: Cumulative Layout Shift] --> J["< 0.1: Tốt"]
C --> K["0.1 - 0.25: Cần cải thiện"]
C --> L["> 0.25: Kém"]
end
style A fill:#d4f9d4,stroke:#05c805
style B fill:#f9f9d4,stroke:#c8c805
style C fill:#d4d4f9,stroke:#0505c8
style D fill:#d4f9d4,stroke:#05c805
style G fill:#d4f9d4,stroke:#05c805
style J fill:#d4f9d4,stroke:#05c805
style E fill:#f9f9d4,stroke:#c8c805
style H fill:#f9f9d4,stroke:#c8c805
style K fill:#f9f9d4,stroke:#c8c805
style F fill:#f9d4d4,stroke:#c80505
style I fill:#f9d4d4,stroke:#c80505
style L fill:#f9d4d4,stroke:#c80505
1. Largest Contentful Paint (LCP)
LCP đo thời điểm mà phần tử nội dung lớn nhất trong viewport được hiển thị. Đây là một chỉ số quan trọng về tốc độ tải trang.
Ngưỡng tốt: Dưới 2.5 giây
Các yếu tố ảnh hưởng đến LCP:
- Thời gian phản hồi server
- Thời gian tải tài nguyên (đặc biệt là hình ảnh lớn)
- Render-blocking JavaScript và CSS
- Client-side rendering
Cách cải thiện:
- Tối ưu hóa server (sử dụng CDN, caching)
- Tối ưu hóa hình ảnh (nén, định dạng hiện đại như WebP)
- Loại bỏ CSS và JavaScript không cần thiết
- Sử dụng preload cho tài nguyên quan trọng
Code demo đo lường LCP:
// Sử dụng Web Vitals API để đo LCP
import { getLCP, getFID, getCLS } from "web-vitals";
// Đo và ghi lại LCP
getLCP(({ name, value, rating }) => {
console.log(`LCP: ${value}ms - Rating: ${rating}`);
// Gửi dữ liệu đến analytics
sendToAnalytics({
name,
value,
rating,
id: "user-123", // ID người dùng
page: window.location.pathname,
});
});
// Hàm gửi dữ liệu đến analytics
function sendToAnalytics(data) {
const url = "https://example.com/analytics";
const body = JSON.stringify(data);
// Sử dụng Beacon API nếu có thể (không chặn main thread)
if (navigator.sendBeacon) {
navigator.sendBeacon(url, body);
} else {
fetch(url, { body, method: "POST", keepalive: true });
}
}
Ví dụ tối ưu hóa LCP:
<!-- Preload hero image để cải thiện LCP -->
<link rel="preload" as="image" href="/hero-image.webp" fetchpriority="high" />
<!-- Inline critical CSS để giảm render-blocking -->
<style>
/* Critical CSS cho above-the-fold content */
.hero {
width: 100%;
height: 50vh;
background-color: #f0f0f0; /* Placeholder color */
}
.hero img {
width: 100%;
height: 100%;
object-fit: cover;
}
</style>
<!-- Defer non-critical CSS -->
<link
rel="stylesheet"
href="/styles.css"
media="print"
onload="this.media='all'"
/>
2. First Input Delay (FID) / Interaction to Next Paint (INP)
FID đo thời gian từ khi người dùng tương tác đầu tiên (như nhấp chuột) đến khi trình duyệt phản hồi. INP là phiên bản mới hơn, đo lường độ trễ tương tác trong toàn bộ phiên của người dùng.
Ngưỡng tốt:
- FID: Dưới 100ms
- INP: Dưới 200ms
Các yếu tố ảnh hưởng:
- JavaScript nặng
- Long tasks trên main thread
- Nhiều event handlers
- Hydration trong frameworks
Cách cải thiện:
- Chia nhỏ code JavaScript (code-splitting)
- Sử dụng Web Workers cho các tác vụ nặng
- Tối ưu hóa event handlers
- Sử dụng requestIdleCallback và requestAnimationFrame
Code demo đo lường FID và INP:
// Đo lường FID
import { getFID, getINP } from "web-vitals";
// Đo FID
getFID(({ name, value, rating }) => {
console.log(`FID: ${value}ms - Rating: ${rating}`);
sendToAnalytics({ name, value, rating });
});
// Đo INP (Interaction to Next Paint)
getINP(({ name, value, rating }) => {
console.log(`INP: ${value}ms - Rating: ${rating}`);
sendToAnalytics({ name, value, rating });
});
Ví dụ tối ưu hóa tương tác:
// Sử dụng Web Worker để xử lý tác vụ nặng
if (window.Worker) {
const worker = new Worker("/js/heavy-task-worker.js");
// Gửi dữ liệu đến worker thay vì xử lý trên main thread
document.querySelector("#process-button").addEventListener("click", () => {
const data = collectDataToProcess();
worker.postMessage(data);
// Hiển thị trạng thái loading
showLoadingState();
});
// Nhận kết quả từ worker
worker.onmessage = function (e) {
// Cập nhật UI với kết quả
updateUIWithResults(e.data);
hideLoadingState();
};
}
// Sử dụng requestAnimationFrame để tối ưu hóa animation
function smoothAnimation() {
// Update animation state
updateAnimationState();
// Schedule next frame
requestAnimationFrame(smoothAnimation);
}
// Bắt đầu animation loop
requestAnimationFrame(smoothAnimation);
3. Cumulative Layout Shift (CLS)
CLS đo lường sự ổn định trực quan của trang, tức là mức độ các phần tử di chuyển sau khi được hiển thị ban đầu.
Ngưỡng tốt: Dưới 0.1
Các yếu tố gây ra layout shift:
- Hình ảnh không có kích thước xác định
- Quảng cáo, embeds, iframes không có kích thước dự trữ
- Font FOUT/FOIT (Flash of Unstyled Text/Invisible Text)
- Nội dung được chèn động
Cách cải thiện:
- Luôn chỉ định kích thước cho hình ảnh và video (
width
vàheight
) - Dự trữ không gian cho quảng cáo
- Sử dụng
font-display: swap
và preload fonts - Tránh chèn nội dung phía trên nội dung hiện có
Code demo đo lường CLS:
// Đo lường CLS
import { getCLS } from "web-vitals";
getCLS(({ name, value, rating }) => {
console.log(`CLS: ${value} - Rating: ${rating}`);
sendToAnalytics({ name, value, rating });
});
// Theo dõi layout shifts cụ thể để debug
if (typeof PerformanceObserver !== "undefined") {
// Tạo observer để theo dõi layout-shift
const layoutShiftObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Chỉ log các layout shift có giá trị đáng kể
if (!entry.hadRecentInput && entry.value >= 0.01) {
console.log("Layout shift:", {
value: entry.value,
elements: entry.sources.map((source) => {
return {
node: source.node,
previousRect: source.previousRect,
currentRect: source.currentRect,
};
}),
});
}
}
});
// Bắt đầu quan sát layout shifts
layoutShiftObserver.observe({ type: "layout-shift", buffered: true });
}
Ví dụ tối ưu hóa CLS:
<!-- Tối ưu hóa hình ảnh để tránh layout shift -->
<style>
.image-container {
aspect-ratio: 16/9; /* Giữ tỷ lệ khung hình */
width: 100%;
background-color: #f0f0f0; /* Placeholder color */
overflow: hidden;
}
</style>
<div class="image-container">
<img
src="/example.jpg"
width="800"
height="450"
loading="lazy"
alt="Mô tả hình ảnh"
/>
</div>
<!-- Tối ưu hóa font loading -->
<link
rel="preload"
href="/fonts/custom-font.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<style>
@font-face {
font-family: "CustomFont";
font-style: normal;
font-weight: 400;
font-display: swap; /* Tránh FOIT */
src: url("/fonts/custom-font.woff2") format("woff2");
}
</style>
<!-- Dự trữ không gian cho nội dung động -->
<div style="min-height: 250px; width: 100%;">
<!-- Nội dung sẽ được tải động vào đây -->
<div id="dynamic-content"></div>
</div>
4. Total Blocking Time (TBT)
TBT đo tổng thời gian mà main thread bị chặn, ngăn phản hồi đầu vào của người dùng.
Ngưỡng tốt: Dưới 200ms
Cách cải thiện:
- Chia nhỏ các tác vụ JavaScript dài
- Sử dụng Web Workers
- Tối ưu hóa JavaScript (loại bỏ code không sử dụng)
- Lazy-load JavaScript không cần thiết ngay lập tức
Code demo giảm TBT:
// Chia nhỏ tác vụ dài thành các phần nhỏ hơn
function processLargeArray(array) {
// Kích thước mỗi phần xử lý
const chunkSize = 1000;
let index = 0;
function processChunk() {
// Lấy phần tiếp theo của mảng để xử lý
const chunk = array.slice(index, index + chunkSize);
index += chunkSize;
// Xử lý phần này
chunk.forEach((item) => {
// Xử lý từng item
processItem(item);
});
// Hiển thị tiến trình
updateProgressBar(index / array.length);
// Nếu còn dữ liệu, lên lịch xử lý phần tiếp theo
if (index < array.length) {
// Sử dụng setTimeout để nhường main thread
setTimeout(processChunk, 0);
} else {
// Hoàn thành
finishProcessing();
}
}
// Bắt đầu xử lý
processChunk();
}
// Sử dụng code splitting với dynamic import
const button = document.querySelector("#feature-button");
button.addEventListener("click", async () => {
// Hiển thị loading state
button.disabled = true;
button.textContent = "Loading...";
try {
// Chỉ tải module khi cần
const { initFeature } = await import("./feature.js");
initFeature();
} catch (error) {
console.error("Failed to load feature:", error);
} finally {
// Khôi phục trạng thái button
button.disabled = false;
button.textContent = "Feature Loaded";
}
});
5. Time to Interactive (TTI)
TTI đo thời gian từ khi bắt đầu tải trang đến khi trang có thể tương tác đầy đủ.
Ngưỡng tốt: Dưới 3.8 giây
Cách cải thiện:
- Giảm thiểu JavaScript
- Loại bỏ JavaScript không cần thiết
- Chia nhỏ code
- Tối ưu hóa Critical Rendering Path
Code demo đo lường và cải thiện TTI:
// Đo lường TTI
import { getTTFB, getTTI } from "web-vitals";
// Time to First Byte
getTTFB(({ name, value }) => {
console.log(`TTFB: ${value}ms`);
sendToAnalytics({ name, value });
});
// Time to Interactive
getTTI(({ name, value }) => {
console.log(`TTI: ${value}ms`);
sendToAnalytics({ name, value });
});
// Cải thiện TTI bằng cách tải JavaScript theo thứ tự ưu tiên
document.addEventListener("DOMContentLoaded", () => {
// Tải các script quan trọng trước
loadPriorityScripts().then(() => {
// Đánh dấu trang đã sẵn sàng tương tác cơ bản
markAsInteractive();
// Sau đó tải các script ít quan trọng hơn
loadNonCriticalScripts();
});
});
// Thêm thuộc tính defer hoặc async cho scripts
// <script src="analytics.js" defer></script>
// <script src="non-critical.js" async></script>
// Sử dụng Priority Hints (đang thử nghiệm)
// <script src="critical.js" fetchpriority="high"></script>
// <link rel="stylesheet" href="critical.css" fetchpriority="high">
Ví dụ cấu hình webpack cho code splitting:
// webpack.config.js
module.exports = {
// ...
optimization: {
splitChunks: {
chunks: "all",
maxInitialRequests: 25,
minSize: 20000,
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name(module) {
// Lấy tên package từ node_modules
const packageName = module.context.match(
/[\\/]node_modules[\\/]([^@]\w+)/
)[1];
return `vendor.${packageName}`;
},
},
},
},
},
};
Công cụ đo lường và phân tích hiệu suất
Để tối ưu hóa hiệu quả, chúng ta cần công cụ để đo lường và phân tích hiệu suất trang web.
flowchart LR
A["Phân tích Hiệu suất"] --> B["Chrome DevTools"]
A --> C["Lighthouse"]
A --> D["PageSpeed Insights"]
A --> E["WebPageTest"]
B --> F["Performance Tab"]
B --> G["Network Tab"]
B --> H["Memory Tab"]
C --> I["Hiệu suất"]
C --> J["Accessibility"]
C --> K["SEO"]
D --> L["Dữ liệu phòng thí nghiệm"]
D --> M["Dữ liệu thực tế"]
E --> N["Waterfall Charts"]
E --> O["Nhiều vị trí địa lý"]
E --> P["Mô phỏng điều kiện mạng"]
style A fill:#f9d4d4,stroke:#c80505
style B fill:#d4f9d4,stroke:#05c805
style C fill:#d4d4f9,stroke:#0505c8
style D fill:#f9f9d4,stroke:#c8c805
style E fill:#f9d4f9,stroke:#c805c8
1. Chrome DevTools Performance Tab
Chrome DevTools cung cấp một bộ công cụ mạnh mẽ để phân tích hiệu suất:
Tính năng chính:
- Ghi lại và phân tích hoạt động của trang
- Xem timeline của các sự kiện (network, rendering, JavaScript)
- Xác định long tasks và bottlenecks
- Phân tích các giai đoạn của CRP
- Xem các frame drops và jank
Cách sử dụng:
- Mở Chrome DevTools (F12 hoặc Cmd+Option+I trên Mac)
- Chuyển đến tab Performance
- Nhấn nút Record và tương tác với trang
- Dừng ghi và phân tích kết quả
2. Lighthouse
Lighthouse là công cụ tự động hóa của Google để đánh giá hiệu suất, accessibility, SEO và các khía cạnh khác của trang web.
Tính năng chính:
- Đánh giá tổng thể về hiệu suất
- Đo lường Core Web Vitals
- Cung cấp gợi ý cải thiện cụ thể
- Tạo báo cáo có thể chia sẻ
Cách sử dụng:
- Mở Chrome DevTools
- Chuyển đến tab Lighthouse
- Chọn các danh mục cần đánh giá
- Nhấn “Generate report”
3. PageSpeed Insights
PageSpeed Insights kết hợp dữ liệu phòng thí nghiệm (từ Lighthouse) và dữ liệu thực tế (từ Chrome User Experience Report).
Tính năng chính:
- Đánh giá hiệu suất trên cả thiết bị di động và máy tính để bàn
- Dữ liệu thực tế từ người dùng thực
- Gợi ý cải thiện chi tiết
- Điểm hiệu suất tổng thể
Cách sử dụng:
- Truy cập PageSpeed Insights
- Nhập URL cần phân tích
- Xem kết quả và gợi ý
4. WebPageTest
WebPageTest là công cụ phân tích hiệu suất nâng cao, cho phép kiểm tra từ nhiều vị trí và điều kiện mạng khác nhau.
Tính năng chính:
- Kiểm tra từ nhiều vị trí địa lý
- Mô phỏng các điều kiện mạng khác nhau
- Waterfall charts chi tiết
- Phân tích First Byte, Start Render, và các chỉ số khác
- So sánh nhiều lần chạy
Cách sử dụng:
- Truy cập WebPageTest
- Nhập URL và cấu hình kiểm tra
- Chạy kiểm tra và phân tích kết quả chi tiết
Ứng dụng thực tế
Hiểu biết về quá trình render của trình duyệt giúp chúng ta xác định và giải quyết các vấn đề hiệu suất một cách hiệu quả. Dưới đây là một số ví dụ thực tế:
Ví dụ 1: Tối ưu hóa LCP
Một trang web có LCP là 5.2 giây, chủ yếu do một hình ảnh hero lớn. Sau khi hiểu về CRP, chúng ta có thể:
- Tối ưu hóa hình ảnh (nén, định dạng WebP)
- Sử dụng
<link rel="preload">
để tải hình ảnh sớm hơn - Cân nhắc sử dụng responsive images với
srcset
- Sử dụng CDN để phân phối hình ảnh nhanh hơn
Kết quả: LCP giảm xuống 2.1 giây.
Ví dụ 2: Giảm CLS
Một trang web thương mại điện tử có CLS cao (0.25) do font tùy chỉnh và hình ảnh sản phẩm không có kích thước xác định. Giải pháp:
- Thêm
width
vàheight
cho tất cả hình ảnh sản phẩm - Sử dụng
font-display: swap
và preload font - Dự trữ không gian cho các phần tử động
Kết quả: CLS giảm xuống 0.05.
Ví dụ 3: Cải thiện FID/INP
Một ứng dụng web có FID cao (250ms) do JavaScript nặng trên main thread. Sau khi phân tích với Chrome DevTools Performance, chúng ta thực hiện:
- Chia nhỏ bundle JavaScript với code-splitting
- Di chuyển xử lý dữ liệu nặng sang Web Worker
- Lazy-load các tính năng không cần thiết ngay lập tức
Kết quả: FID giảm xuống 80ms.
Tối ưu hóa quá trình render
flowchart LR
A["Xác định vấn đề hiệu suất"] --> B["Phân tích CRP"]
B --> C["Tối ưu DOM/CSSOM"]
B --> D["Tối ưu Render Tree"]
B --> E["Giảm thiểu Layout"]
B --> F["Tối ưu Paint"]
B --> G["Tối ưu Composite"]
C --> H["Tối ưu HTML/CSS"]
C --> I["Giảm kích thước JavaScript"]
D --> J["Loại bỏ CSS không sử dụng"]
D --> K["Sử dụng content-visibility"]
E --> L["Tránh forced reflow"]
E --> M["Batch DOM updates"]
F --> N["Sử dụng will-change"]
F --> O["Tối ưu hóa hình ảnh"]
G --> P["Sử dụng transform/opacity"]
G --> Q["Tạo layer riêng biệt"]
style A fill:#f9d4d4,stroke:#c80505
style B fill:#d4f9d4,stroke:#05c805
style C fill:#d4d4f9,stroke:#0505c8
style D fill:#f9f9d4,stroke:#c8c805
style E fill:#f9d4f9,stroke:#c805c8
style F fill:#d4f9f9,stroke:#05c8c8
style G fill:#f9d4d4,stroke:#c80505
Kết luận
Hiểu rõ về Critical Rendering Path và các chỉ số hiệu suất quan trọng là nền tảng cho việc tối ưu hóa frontend hiệu quả. Bằng cách nắm vững cách trình duyệt xử lý và hiển thị nội dung, chúng ta có thể xác định chính xác các vấn đề và áp dụng các giải pháp phù hợp.