Speculation Rules API — Điều hướng web nhanh như chớp với Prefetch và Prerender
Posted on: 4/18/2026 1:09:29 PM
Table of contents
- 1. Speculation Rules API là gì?
- 2. Prefetch vs Prerender — Chọn đúng chiến lược
- 3. Cú pháp JSON và cách triển khai
- 4. Eagerness — Kiểm soát thời điểm kích hoạt
- 5. Giới hạn và cơ chế bảo vệ của Chrome
- 6. Phát hiện và đo lường hiệu quả
- 7. Xử lý các tình huống nguy hiểm
- 8. Triển khai thực tế cho các loại website
- 9. Tác động đến Core Web Vitals
- 10. Tính năng mới: Tag và Target Hint
- 11. Content Security Policy
- 12. Browser Support và Progressive Enhancement
- 13. Checklist triển khai
- Kết luận
Bạn đã bao giờ click vào một link và trang mới hiện ra ngay lập tức — không loading, không flash trắng, không chờ đợi? Đó không phải phép thuật, mà là Speculation Rules API đang hoạt động. Đây là một trong những API trình duyệt mạnh mẽ nhất dành cho web performance, cho phép trang web "đoán trước" người dùng sẽ đi đâu tiếp theo và tải sẵn trang đó trước khi họ click.
1. Speculation Rules API là gì?
Speculation Rules API là API thay thế cho <link rel="prerender"> đã bị deprecated. Nó cho phép developer khai báo các quy tắc suy đoán (speculation rules) bằng JSON, chỉ định những URL nào nên được prefetch (tải trước response) hoặc prerender (render sẵn hoàn toàn trong tab ẩn).
Khi người dùng thực sự navigate đến trang đã được prerender, trình duyệt chỉ cần swap tab ẩn thành tab chính — kết quả là trang hiện ra gần như tức thì.
flowchart LR
A["👤 User đang đọc
trang hiện tại"] --> B["📋 Speculation Rules
phân tích links"]
B --> C{"Prefetch hay
Prerender?"}
C -->|Prefetch| D["📥 Tải response body
(không render)"]
C -->|Prerender| E["🖥️ Render hoàn toàn
trong tab ẩn"]
D --> F["⚡ User click →
Tải nhanh hơn"]
E --> G["⚡ User click →
Hiển thị tức thì"]
style A fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style B fill:#e94560,stroke:#fff,color:#fff
style C fill:#2c3e50,stroke:#fff,color:#fff
style D fill:#f8f9fa,stroke:#4CAF50,color:#2c3e50
style E fill:#4CAF50,stroke:#fff,color:#fff
style F fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style G fill:#e94560,stroke:#fff,color:#fff
2. Prefetch vs Prerender — Chọn đúng chiến lược
Hai chiến lược này khác nhau đáng kể về chi phí và hiệu quả:
| Tiêu chí | Prefetch | Prerender |
|---|---|---|
| Hoạt động | Tải response body (HTML) | Tải + render hoàn toàn trong tab ẩn |
| Subresources (CSS, JS, ảnh) | Không tải | Tải tất cả |
| JavaScript | Không execute | Execute đầy đủ |
| Chi phí bộ nhớ | Thấp | Cao (tương đương 1 iframe) |
| Tốc độ cải thiện | Trung bình — tiết kiệm network round-trip | Gần tức thì — trang đã sẵn sàng |
| Cross-origin | Same-site (không cookies) | Same-origin mặc định |
| Cache | In-memory, 5 phút | In-memory, 5 phút |
| Nên dùng khi | Nhiều trang có thể được truy cập | Trang gần chắc chắn sẽ được truy cập |
💡 Quy tắc vàng
Prefetch rộng, prerender hẹp. Prefetch nhiều trang vì chi phí thấp. Prerender chỉ 1-2 trang mà bạn tin chắc (>50%) user sẽ navigate đến.
3. Cú pháp JSON và cách triển khai
Speculation rules được khai báo trong thẻ <script type="speculationrules">:
3.1. List Rules — Chỉ định URL cụ thể
<script type="speculationrules">
{
"prerender": [{
"urls": ["/san-pham/hot-deal", "/gio-hang"]
}],
"prefetch": [{
"urls": ["/blog", "/lien-he", "/gioi-thieu"]
}]
}
</script>List rules phù hợp khi bạn biết chính xác URL nào cần tải trước — ví dụ trang giỏ hàng trên e-commerce, hoặc bài viết tiếp theo trên blog.
3.2. Document Rules — Tự động dựa trên selector và URL pattern
<script type="speculationrules">
{
"prerender": [{
"where": {
"and": [
{ "href_matches": "/*" },
{ "not": { "href_matches": "/admin/*" } },
{ "not": { "href_matches": "/logout" } },
{ "not": { "href_matches": "/*?*(^|&)add-to-cart=*" } },
{ "not": { "selector_matches": ".no-prerender" } },
{ "not": { "selector_matches": "[rel~=nofollow]" } }
]
},
"eagerness": "moderate"
}]
}
</script>Document rules mạnh mẽ hơn vì tự động áp dụng cho mọi link trên trang mà match điều kiện. Bạn không cần liệt kê từng URL — chỉ cần loại trừ những URL không nên prerender.
3.3. Khai báo qua HTTP Header
Từ Chrome 121+, bạn có thể serve speculation rules qua HTTP header thay vì inline script:
Speculation-Rules: "/speculationrules.json"File JSON phải được serve với MIME type application/speculationrules+json và pass CORS check nếu cross-origin.
4. Eagerness — Kiểm soát thời điểm kích hoạt
Thuộc tính eagerness quyết định khi nào trình duyệt bắt đầu speculation:
| Eagerness | Desktop | Mobile | Phù hợp cho |
|---|---|---|---|
| immediate | Ngay khi rules được parse | URL chắc chắn (homepage → dashboard) | |
| eager | Hover 10ms | Link vào viewport 50ms | Navigation chính trong menu |
| moderate | Hover 200ms hoặc pointerdown | Scroll dừng + viewport heuristic 500ms | Link trong nội dung bài viết |
| conservative | Pointer down / touch start | Trang nặng, cần tiết kiệm tài nguyên | |
Mặc định
List rules mặc định immediate — tải ngay khi parse. Document rules mặc định conservative — chỉ tải khi user bắt đầu tương tác (pointer down). Đa số trường hợp nên dùng moderate cho document rules để cân bằng tốc độ và tài nguyên.
flowchart TD
A["Speculation Rules
được parse"] --> B{"Eagerness?"}
B -->|immediate| C["Tải ngay lập tức"]
B -->|eager| D["Hover 10ms (Desktop)
Viewport 50ms (Mobile)"]
B -->|moderate| E["Hover 200ms (Desktop)
Scroll stop 500ms (Mobile)"]
B -->|conservative| F["Pointer down /
Touch start"]
C --> G["Prefetch / Prerender
bắt đầu"]
D --> G
E --> G
F --> G
style A fill:#e94560,stroke:#fff,color:#fff
style B fill:#2c3e50,stroke:#fff,color:#fff
style C fill:#4CAF50,stroke:#fff,color:#fff
style D fill:#f8f9fa,stroke:#4CAF50,color:#2c3e50
style E fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style F fill:#f8f9fa,stroke:#ff9800,color:#2c3e50
style G fill:#e94560,stroke:#fff,color:#fff
5. Giới hạn và cơ chế bảo vệ của Chrome
Chrome đặt ra các giới hạn để tránh lạm dụng tài nguyên:
| Eagerness | Prefetch tối đa | Prerender tối đa | Hành vi khi đầy |
|---|---|---|---|
| immediate / eager | 50 | 10 | Từ chối thêm mới |
| moderate / conservative | 2 | 2 | FIFO — huỷ cũ nhất |
Ngoài ra, Chrome sẽ tự động chặn speculation khi:
- Save-Data được bật — user đang tiết kiệm dữ liệu
- Energy Saver mode với pin yếu
- Bộ nhớ thấp — thiết bị không đủ RAM
- "Preload pages" bị tắt trong Chrome Settings
- Tab ở background — không lãng phí tài nguyên cho tab không nhìn thấy
⚠️ Prerender bị huỷ khi gặp
Các trang có alert(), confirm(), prompt(), yêu cầu geolocation, camera, hoặc notification sẽ bị huỷ prerender. Các API này được deferred (tạm dừng) cho đến khi trang thực sự activate. Tránh đặt chúng trong quá trình load ban đầu.
6. Phát hiện và đo lường hiệu quả
6.1. Feature Detection
if (HTMLScriptElement.supports &&
HTMLScriptElement.supports("speculationrules")) {
// Trình duyệt hỗ trợ Speculation Rules
const specScript = document.createElement("script");
specScript.type = "speculationrules";
specScript.textContent = JSON.stringify({
prefetch: [{ urls: ["/next-page"] }]
});
document.body.append(specScript);
} else {
// Fallback: dùng <link rel="prefetch">
const link = document.createElement("link");
link.rel = "prefetch";
link.href = "/next-page";
document.head.append(link);
}6.2. Server-side Detection qua Sec-Purpose Header
Request từ speculation sẽ kèm header Sec-Purpose:
// Prefetch request
Sec-Purpose: prefetch
// Prerender request
Sec-Purpose: prefetch;prerenderServer có thể dùng header này để bỏ qua side-effects — ví dụ không ghi analytics, không trigger email notification cho prefetch/prerender request.
6.3. Client-side Detection
// Kiểm tra trang có đang trong trạng thái prerendering?
if (document.prerendering) {
// Defer analytics, mutations...
document.addEventListener("prerenderingchange", () => {
// Trang đã activate — chạy analytics
gtag("event", "page_view", { prerendered: true });
}, { once: true });
}
// Kiểm tra trang có được prefetch không?
const navEntry = performance.getEntriesByType("navigation")[0];
if (navEntry.deliveryType === "navigational-prefetch") {
console.log("Trang này được tải từ prefetch cache");
}
// Đo activation time cho prerender
if (navEntry.activationStart > 0) {
const prerenderTime = navEntry.activationStart;
console.log(`Prerender activation sau ${prerenderTime}ms`);
}7. Xử lý các tình huống nguy hiểm
Không phải URL nào cũng nên prefetch/prerender. Một số URL có side-effects khi được request:
flowchart TD
A["🔗 URL cần
speculation"] --> B{"Có side-effect
không?"}
B -->|Không| C["✅ An toàn
Prefetch/Prerender"]
B -->|Có| D{"Loại
side-effect?"}
D -->|Logout/Auth| E["❌ Loại trừ
khỏi rules"]
D -->|Analytics| F["⏸️ Defer
qua prerenderingchange"]
D -->|Add to cart| G["❌ Loại trừ
khỏi rules"]
D -->|Storage mutation| H["⏸️ Defer
qua prerenderingchange"]
style A fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style B fill:#2c3e50,stroke:#fff,color:#fff
style C fill:#4CAF50,stroke:#fff,color:#fff
style D fill:#e94560,stroke:#fff,color:#fff
style E fill:#ff9800,stroke:#fff,color:#fff
style F fill:#f8f9fa,stroke:#4CAF50,color:#2c3e50
style G fill:#ff9800,stroke:#fff,color:#fff
style H fill:#f8f9fa,stroke:#4CAF50,color:#2c3e50
Pattern an toàn cho Analytics
// Đợi trang thực sự được user nhìn thấy rồi mới track
function initAnalytics() {
gtag("config", "GA_ID");
gtag("event", "page_view");
}
if (document.prerendering) {
document.addEventListener("prerenderingchange", initAnalytics,
{ once: true });
} else {
initAnalytics();
}Pattern cho Server-side (ASP.NET Core)
app.Use(async (context, next) => {
var secPurpose = context.Request.Headers["Sec-Purpose"].ToString();
if (secPurpose.Contains("prefetch") ||
secPurpose.Contains("prerender")) {
// Bỏ qua side-effects cho speculation request
context.Items["IsSpeculation"] = true;
}
await next();
});
// Trong controller/endpoint:
if (HttpContext.Items.ContainsKey("IsSpeculation")) {
// Không gửi email, không ghi audit log
return View(model);
}8. Triển khai thực tế cho các loại website
8.1. Blog / Content Site
<script type="speculationrules">
{
"prerender": [{
"where": {
"and": [
{ "href_matches": "/blog/*" },
{ "not": { "selector_matches": "[rel~=nofollow]" } }
]
},
"eagerness": "moderate"
}],
"prefetch": [{
"where": { "href_matches": "/tag/*" },
"eagerness": "conservative"
}]
}
</script>8.2. E-commerce
<script type="speculationrules">
{
"prerender": [{
"where": {
"and": [
{ "href_matches": "/san-pham/*" },
{ "not": { "href_matches": "/*?*add-to-cart=*" } },
{ "not": { "href_matches": "/checkout*" } },
{ "not": { "href_matches": "/thanh-toan*" } }
]
},
"eagerness": "moderate"
}],
"prefetch": [{
"urls": ["/gio-hang"],
"eagerness": "conservative"
}]
}
</script>8.3. SPA với Vue.js / Nuxt — Kết hợp cùng Router
// plugins/speculation-rules.client.ts (Nuxt 3)
export default defineNuxtPlugin(() => {
if (!HTMLScriptElement.supports?.("speculationrules")) return;
const router = useRouter();
router.afterEach((to) => {
// Xoá rules cũ
document.querySelectorAll('script[type="speculationrules"]')
.forEach(el => el.remove());
// Tạo rules mới dựa trên route hiện tại
const rules = buildRulesForRoute(to.path);
if (!rules) return;
const script = document.createElement("script");
script.type = "speculationrules";
script.textContent = JSON.stringify(rules);
document.body.append(script);
});
});
function buildRulesForRoute(path: string) {
// Blog: prerender bài tiếp theo
if (path.startsWith("/blog/")) {
return {
prerender: [{
where: {
and: [
{ selector_matches: ".next-post a, .related-posts a" }
]
},
eagerness: "moderate"
}]
};
}
// Trang chủ: prefetch các mục chính
if (path === "/") {
return {
prefetch: [{
where: { selector_matches: ".featured-links a" },
eagerness: "eager"
}]
};
}
return null;
}9. Tác động đến Core Web Vitals
Speculation Rules API cải thiện đáng kể các chỉ số Core Web Vitals khi trang được prerender thành công:
💡 Khi prerender chưa hoàn tất
Nếu user navigate trước khi prerender xong, trang sẽ tiếp tục load ở foreground — vẫn có head-start advantage so với load từ đầu. Không bao giờ chậm hơn trường hợp không có speculation.
10. Tính năng mới: Tag và Target Hint
Tag Field (Chrome 136+)
Gắn label cho rules để server-side filtering qua CDN:
{
"tag": "product-prerender",
"prerender": [{
"urls": ["/san-pham/moi-nhat"]
}]
}Server nhận header Sec-Speculation-Tags: product-prerender — CDN có thể phân biệt speculation request từ site vs từ browser tự động.
Target Hint (Chrome 138+, experimental)
{
"prerender": [{
"urls": ["/external-page"],
"target_hint": "_blank"
}]
}Cho phép prerender trang sẽ được mở trong tab mới — hữu ích cho link target="_blank".
11. Content Security Policy
Nếu site dùng CSP, cần thêm directive cho inline speculation rules:
Content-Security-Policy: script-src 'self' 'inline-speculation-rules'Hoặc dùng nonce/hash như với script thông thường. Nếu không có directive này, inline <script type="speculationrules"> sẽ bị chặn.
12. Browser Support và Progressive Enhancement
| Trình duyệt | Prefetch | Prerender | Document Rules | Eagerness |
|---|---|---|---|---|
| Chrome 109+ | ✅ | ✅ | ✅ (121+) | ✅ (121+) |
| Edge 109+ | ✅ | ✅ | ✅ (121+) | ✅ (121+) |
| Firefox | ❌ | ❌ | ❌ | ❌ |
| Safari | ⚠️ Behind flag | ⚠️ Behind flag | — | — |
Progressive Enhancement — không lo break
Speculation Rules API là progressive enhancement thuần tuý. Trình duyệt không hỗ trợ sẽ bỏ qua <script type="speculationrules"> hoàn toàn — không lỗi, không ảnh hưởng. Bạn có thể triển khai ngay mà không sợ break trải nghiệm trên Firefox hay Safari.
13. Checklist triển khai
Trước khi đưa Speculation Rules vào production, đảm bảo kiểm tra:
- Xác định URL an toàn: Loại trừ logout, checkout, add-to-cart, và mọi URL có side-effect
- Chọn eagerness phù hợp:
moderatecho phần lớn trường hợp,immediatecho navigation chắc chắn - Defer analytics: Dùng
prerenderingchangeevent để không track prerender dưới dạng page view thật - Kiểm tra Sec-Purpose server-side: Bỏ qua side-effects cho speculation request
- Thêm CSP directive:
'inline-speculation-rules'nếu site dùng Content Security Policy - Test trên Chrome DevTools: Kiểm tra tab Application → Speculative loads để xem prerender status
- Đo lường: So sánh Core Web Vitals trước/sau bằng CrUX hoặc RUM data
Kết luận
Speculation Rules API đánh dấu bước tiến lớn trong web performance — lần đầu tiên developer có công cụ native, khai báo bằng JSON đơn giản, để đạt được near-instant navigation mà không cần framework phức tạp hay service worker. Với tính chất progressive enhancement, bạn có thể triển khai ngay hôm nay và user trên Chrome/Edge sẽ được hưởng lợi ngay lập tức, trong khi các trình duyệt khác hoạt động bình thường.
Điều quan trọng nhất: prefetch rộng, prerender hẹp, defer side-effects — ba nguyên tắc này đủ để bạn triển khai an toàn và hiệu quả trên mọi loại website.
💡 Bắt đầu từ đâu?
Thêm một thẻ <script type="speculationrules"> đơn giản với document rules + moderate eagerness cho internal links. Chỉ mất 10 dòng code nhưng có thể giảm LCP của navigation tiếp theo xuống gần 0.
Nguồn tham khảo:
Disclaimer: The opinions expressed in this blog are solely my own and do not reflect the views or opinions of my employer or any affiliated organizations. The content provided is for informational and educational purposes only and should not be taken as professional advice. While I strive to provide accurate and up-to-date information, I make no warranties or guarantees about the completeness, reliability, or accuracy of the content. Readers are encouraged to verify the information and seek independent advice as needed. I disclaim any liability for decisions or actions taken based on the content of this blog.