想讓網站在沒網路也能開、重複資源不再每次都下載、頁面秒開又省流量?這些日常體驗的升級,靠的就是 Service Worker。它像「瀏覽器內建的代理層」,能攔截請求、回傳快取、再視情況呼叫網路,讓你的網站具備:
很棒吧!就讓我們看下去~ 🛜
傳統網頁一關就消失,沒辦法在背景持續工作,也無法在離線時回應請求。Service Worker 改變了這件事:
心智模型:把它想像成「瀏覽器內建的反向代理 + 小型背景服務」。
window
或 document
postMessage
進行fetch
請求,都會先經過 Service Workerlocalhost
例外跟頁面獨立,有自己完整的流程:
navigator.serviceWorker.register()
,瀏覽器會檢查是否已有相同的 Service Worker,並偵測檔案是否有更新。限制:
首先在根目錄建立 sw.js(Service Worker 腳本),然後註冊 Service Worker。
在頁面 JS:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(() => console.log('✅ Service Worker 註冊成功'))
.catch(err => console.error('❌ 註冊失敗:', err));
}
常見的用途是預快取資源。
在 sw.js
:
const CACHE_NAME = 'my-cache-v1';
const ASSETS = ['/index.html', '/style.css', '/script.js'];
self.addEventListener('install', (event) => {
console.log('📦 Service Worker 安裝');
// 安裝完成前先把必要資源寫入快取;waitUntil 會延後 install 結束直到 Promise 完成
event.waitUntil(
caches.open(CACHE_NAME).then(cache => cache.addAll(ASSETS))
);
});
event.waitUntil()
會延遲安裝完成,直到快取寫入完畢。
install 完成後,新版 SW 會嘗試進入 activate。若是第一次安裝,會馬上啟用;若是更新,則需要等舊版頁面全部關閉後才會 activate。
常見的用途是刪除舊版本的快取,避免佔用空間或讀到舊檔案。
在 sw.js
:
self.addEventListener('activate', (event) => {
console.log('🚀 Service Worker 啟用');
// 在啟用時清理舊版快取:避免讀到過期資源、釋放空間
event.waitUntil(
caches.keys().then(keys => {
return Promise.all(
keys.filter(k => k !== CACHE_NAME).map(k => caches.delete(k))
);
})
);
});
最常見的邏輯是「快取優先,沒有再打網路」,這樣當使用者沒網路時,仍然可以讀到快取的頁面或資源。
在 sw.js
:
self.addEventListener('fetch', (event) => {
event.respondWith(
// 先查快取:若已有對應的 Response,直接回快取(Cache First)
caches.match(event.request).then(cached => {
return cached || fetch(event.request);
})
);
});
這部分有點複雜,很容易搞混,來考驗一下大家對生命週期的理解,也幫助釐清觀念。
sw.js
,會先 註冊(register);因為沒有舊版本,所以馬上觸發 安裝(install),將資源快取好;接著執行 啟用(activate),正式接管網站。sw.js
的檔案有更新,會先 註冊(register) 並觸發新的 安裝(install)。舊的 SW 還在控制頁面,新的 SW 會進入 waiting 狀態,等待所有使用舊版 SW 的頁面關閉後才進入 啟用(activate)。一旦啟用成功,新版 SW 接管控制權,舊版就會被清除。這就是「版本更新」的典型流程。圖示:sw.js 檔案異動後,等待所有使用舊版 SW 的頁面關閉後才進入 啟用(activate)
小結:
這樣一比較,就能清楚知道什麼情境下會觸發哪些事件了!
大家應該有比較清楚 Service Worker 生命週期了吧~ 😇
Cache API 是專為 Service Worker 設計的儲存機制,用於快取網路請求和回應。透過全域的 caches
物件,可以輕鬆管理多個快取空間。
caches.open(name)
→ 開啟/建立快取空間。cache.addAll(urls)
→ 一次加入多個資源,內部會逐一發送 fetch 請求。任一資源失敗(404、網路錯誤等)會導致整個 Promise reject。正式專案建議改用逐筆 cache.put()
,提高容錯能力。caches.match(request)
→ 查詢快取。cache.put(request, response)
→ 手動新增快取。caches.delete(name)
→ 刪除快取空間。這比 localStorage / IndexedDB 更適合做「網路資源」快取。
今天理解了 Service Worker 的基礎:
install
→ activate
→ fetch
。明天我們會更進一步探討 快取策略(Cache First、Network First、Stale-While-Revalidate)。🔥
👉 歡迎追蹤這個系列,我會從 Canvas 開始,一步步帶你認識更多 Web API 🎯