主題: Web platform
Speculation Rules API:預載不是免費加速,先處理副作用
Speculation Rules 能讓 MPA 的下一頁更快,但 prefetch 與 prerender 的成本不同。先排除有副作用的 URL、保留正常導航,再以 activation 與命中率決定是否擴大。
動態迷因(展開/收合)
第一次看到 Speculation Rules API,很容易想把它當成「讓整站變快的 JSON」。把所有站內連結都預載,看起來不是最有效率嗎?
我現在反而會先問:這個 URL 就算使用者沒有真的前往,先載入會不會做了不該做的事?
這個 API 的目標是未來的整頁導航,不是替 SPA router 偷跑 API 資料。它讓支援的瀏覽器猜下一頁,選擇預先取得文件,或把整個頁面放到隱藏環境跑起來;瀏覽器仍可依記憶體、網路與使用者設定略過這個提示。正常點連結的路徑因此必須一直可用。
先分清:拿一頁,還是先跑一頁
| 動作 | 瀏覽器先做什麼 | 適合的起點 |
|---|---|---|
prefetch |
取得目標文件的 response body,不載入它引用的子資源 | 常見、低成本、可預測的下一頁 |
prerender |
在隱藏頁面中取得、render、執行 JavaScript 與載入子資源 | 命中率很高,且副作用已處理的少數頁面 |
兩者的差距不只是「快一點」或「快很多」。prerender 的成本更接近真的開了一個看不見的分頁:它會消耗網路、記憶體與 CPU;使用者沒有前往時,這些成本多半白費。它預設也只適合 same-origin 文件。
所以對一般 MPA,我會先用 prefetch 驗證假設;不要因為 API 名字裡有 prerender,就把它當成第一步。
URL 是 GET,不代表可以隨便猜
Speculation Rules 會發出未來導航的請求。若你的站把狀態變更藏在 GET URL,或頁面載入本身會做事,猜錯一次就可能讓使用者遇到奇怪結果。
先排除登出、切換語系、加入購物車、確認操作、個人化流程等路徑。下例只考慮文章頁,並把高風險路徑明確留在外面:
<script type="speculationrules">
{
"prefetch": [
{
"where": {
"and": [
{ "href_matches": "/article/*" },
{ "not": { "href_matches": "/logout" } },
{ "not": { "href_matches": "/checkout/*" } }
]
},
"eagerness": "moderate"
}
]
}
</script>
這段不是每個瀏覽器都會執行,也不是按下部署鍵就保證每個連結都被預載。它是支援瀏覽器的漸進增強;不支援時,使用者仍是普通、正確地導航。
若站點有嚴格 Content Security Policy,這個內嵌 JSON script 也要被 script-src 明確允許,例如使用 hash、nonce 或 inline-speculation-rules。這個細節比「在 Chrome 看起來很快」更值得先確認。
prerender 會先跑 JavaScript,副作用要等 activation
prefetch 的風險相對小;prerender 則會讓頁面在使用者真正看到之前執行 JavaScript。自訂 analytics、廣告 impression、寫入 local storage、依登入或購物車狀態 render 的元件,都要重新檢查。
Chrome 的指南指出,Google Analytics 等部分服務已能延後到 activation;但這不是自訂 script、tag manager 或第三方 widget 的通行證。自己的程式應清楚決定什麼可以先跑、什麼必須等使用者真的進頁。
function whenActivated() {
return new Promise((resolve) => {
if (document.prerendering) {
document.addEventListener("prerenderingchange", resolve, { once: true });
} else {
resolve();
}
});
}
async function initSideEffects() {
await whenActivated();
initCustomAnalytics();
refreshCartBadge();
}
void initSideEffects();
延後所有 script 是安全的起點,卻不一定是終點:activation 一次跑太多程式,可能把 INP 問題搬到使用者剛進頁的瞬間。比較好的下一步是逐項檢查:可安全 render 的內容保持預先載入,會記錄、寫入或依即時狀態決定內容的工作再等 activation。
動態迷因(展開/收合)
從一兩個高機率頁面開始量
適合測試的候選通常有兩個特徵:下一步很可預測,且頁面很便宜。例如文章列表到熱門文章、固定流程的下一步,或使用者已明確 hover 的單一連結。低命中率的全站規則只是在替使用者多花流量。
我會一起看三件事:
- 預載要求與實際 activation 的比例,判斷猜測是否命中。
- 真的被啟用的頁面,LCP/INP 與導覽時間是否改善。
- 手機網路、server load 與未命中時的浪費是否仍在可接受範圍。
Chrome DevTools 的 Application → Background services → Speculative loads 能顯示規則、候選 URL 與失敗原因;這比只看首頁變快更能回答「這條 rule 到底有沒有生效」。對已 prerender 後被啟用的頁面,navigation timing 的 activationStart 也能協助分開量測。
Speculation Rules API 目前不是 Baseline。這不是拒用理由,卻是設計提醒:把它放在正常導航之上,別讓它成為正確性前提。
我學到什麼
- 我把「下一頁很快」看成 document lifecycle 的優化,不把它混成 SPA route 或一般資源 preload。
prefetch先驗證使用者旅程;prerender只留給高命中、無副作用且可處理 activation 的頁面。- 速度改善必須同時看命中率、互動指標與資源浪費;一次猜對的 demo 不等於適合全站開啟。