這個程式碼研究室是 Google Developers 訓練團隊開發的「開發漸進式網頁應用程式」訓練課程的一部分。建議您依序完成程式碼研究室,充分體驗本課程的價值。
如要瞭解課程的完整詳細資料,請參閱開發漸進式網頁應用程式總覽。
簡介
本實驗室將逐步說明如何建立簡單的 Service Worker,並解釋 Service Worker 的生命週期。
課程內容
- 建立基本服務工作人員指令碼、安裝指令碼,並進行簡單的偵錯
注意事項
- 基本 JavaScript 和 HTML
- ES2015 Promise 的概念和基本語法
- 如何啟用開發人員控制台
開始前的準備事項
- 可存取終端機/殼層的電腦
- 網際網路連線
- 支援 Service Worker 的瀏覽器
- 文字編輯器
從 GitHub 下載或複製 pwa-training-labs 存放區,並視需要安裝 Node.js 的 LTS 版本。
前往 service-worker-lab/app/ 目錄,然後啟動本機開發伺服器:
cd service-worker-lab/app npm install node server.js
你可以隨時使用 Ctrl-c 終止伺服器。
開啟瀏覽器並前往 localhost:8081/。
注意:取消註冊所有 Service Worker,並清除 localhost 的所有 Service Worker 快取,以免干擾實驗室。在 Chrome 開發人員工具中,按一下「應用程式」分頁的「清除儲存空間」部分中的「清除網站資料」,即可達成這個目標。
使用偏好的文字編輯器開啟 service-worker-lab/app/ 資料夾。您將在 app/ 資料夾中建構實驗室。
這個資料夾包含:
below/another.html、js/another.js、js/other.js和other.html是我們用來實驗 Service Worker 範圍的範例資源styles/資料夾包含本實驗室的層疊樣式表test/資料夾包含用於測試進度的檔案index.html是範例網站/應用程式的主要 HTML 網頁service-worker.js是用來建立 Service Worker 的 JavaScript 檔案package.json和package-lock.json會追蹤這個專案中使用的節點套件server.js是用來代管應用程式的簡易 Express 伺服器
在文字編輯器中開啟 service-worker.js。請注意,檔案中沒有任何內容。我們尚未新增任何要在 Service Worker 中執行的程式碼。
在文字編輯器中開啟 index.html。
在 <script> 標記中,加入下列程式碼來註冊 Service Worker:
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('service-worker.js')
.then(registration => {
console.log('Service Worker is registered', registration);
})
.catch(err => {
console.error('Registration failed:', err);
});
});
}儲存指令碼並重新整理頁面。控制台應會傳回訊息,指出服務工作人員已註冊。在 Chrome 中,您可以開啟開發人員工具 (在 Windows 和 Linux 上按 Control + Shift + I 鍵,或在 Mac 上按 ⌘ + Alt + I 鍵),然後依序點選「應用程式」分頁和「服務工作人員」選項,確認服務工作人員是否已註冊。您應該會看到類似下列的輸出:

選用:在不支援的瀏覽器中開啟網站,確認支援檢查條件式是否正常運作。
說明
上述程式碼會將 service-worker.js 檔案註冊為 Service Worker。系統會先檢查瀏覽器是否支援 Service Worker。每次註冊 Service Worker 時都應執行這項操作,因為部分瀏覽器可能不支援 Service Worker。接著,程式碼會使用 ServiceWorkerContainer API 的 register 方法註冊 Service Worker,該 API 包含在視窗的 Navigator 介面中。
服務工作站成功註冊後,navigator.serviceWorker.register(...) 會傳回以 registration 物件解析的 Promise。如果註冊失敗,Promise 會拒絕。
Service worker 狀態的變更會在 service worker 中觸發事件。
新增事件接聽程式
在文字編輯器中開啟 service-worker.js。
將下列事件監聽器新增至服務工作人員:
self.addEventListener('install', event => {
console.log('Service worker installing...');
// Add a call to skipWaiting here
});
self.addEventListener('activate', event => {
console.log('Service worker activating...');
});儲存檔案。
手動取消註冊 Service Worker,然後重新整理頁面,安裝並啟用更新後的 Service Worker。主控台記錄應會指出已註冊、安裝及啟用新的 Service Worker。
注意: 註冊記錄的顯示順序可能與其他記錄 (安裝和啟用) 不同。Service Worker 會與網頁並行執行,因此我們無法保證記錄的順序 (註冊記錄來自網頁,而安裝和啟用記錄來自 Service Worker)。不過,安裝、啟用和其他 Service Worker 事件會在 Service Worker 內依特定順序發生,且一律會依預期順序顯示。
說明
服務工作人員會在註冊程序結束時發出 install 事件。在上述程式碼中,訊息會記錄在 install 事件監聽器內,但在實際應用程式中,這會是快取靜態資產的好地方。
註冊 Service Worker 時,瀏覽器會偵測 Service Worker 是否為新版本 (與先前安裝的 Service Worker 不同,或網站沒有已註冊的 Service Worker)。如果服務工作人員是新的 (本例就是如此),瀏覽器就會安裝。
Service Worker 接管網頁時,會發出 activate 事件。上述程式碼會在這邊記錄訊息,但這個事件通常用於更新快取。
在特定範圍內,一次只能啟用一個 Service Worker (請參閱「探索 Service Worker 範圍」),因此新安裝的 Service Worker 不會啟用,直到現有的 Service Worker 不再使用為止。因此,必須先關閉由 Service Worker 控制的所有網頁,新的 Service Worker 才能接管。由於我們取消註冊了現有的 Service Worker,因此新的 Service Worker 立即啟動。
注意:單純重新整理網頁不足以將控制權轉移給新的 Service Worker,因為系統會在卸載目前網頁前要求新網頁,且舊的 Service Worker 不會閒置。
注意:您也可以使用部分瀏覽器的開發人員工具手動啟用新的 Service Worker,或透過 skipWaiting() 以程式輔助方式啟用,詳情請參閱第 3.4 節。
更新 Service Worker
在 service-worker.js 的任意位置新增下列註解:
// I'm a new service worker儲存檔案並重新整理頁面。查看控制台中的記錄,請注意,新的 Service Worker 會安裝,但不會啟用。在 Chrome 中,您可以在開發人員工具的「應用程式」分頁中查看等待中的 Service Worker。

關閉與 Service Worker 相關聯的所有網頁。然後重新開啟 localhost:8081/。控制台記錄應會指出新的 Service Worker 現已啟用。
注意:如果結果不符預期,請確認開發人員工具中的 HTTP 快取已停用。
說明
瀏覽器會偵測到新舊服務工作人員檔案之間的位元組差異 (因為新增了註解),因此會安裝新的服務工作人員。由於一次只能啟用一個 Service Worker (適用於特定範圍),即使安裝了新的 Service Worker,系統也不會啟用,直到現有的 Service Worker 不再使用為止。關閉舊版 Service Worker 控制的所有網頁,即可啟用新版 Service Worker。
略過等待階段
即使有現有的 Service Worker,只要略過等待階段,新的 Service Worker 就能立即啟動。
在 service-worker.js 中,於 install 事件監聽器中新增對 skipWaiting 的呼叫:
self.skipWaiting();儲存檔案並重新整理頁面。請注意,即使先前的 Service Worker 處於控管狀態,新的 Service Worker 仍會立即安裝並啟用。
說明
skipWaiting() 方法可讓服務工作人員在安裝完成後立即啟動。安裝事件監聽器是放置 skipWaiting() 呼叫的常見位置,但也可以在等待階段期間或之前呼叫。如要進一步瞭解使用 skipWaiting() 的時機和方式,請參閱這份說明文件。在實驗室的其餘部分,我們現在可以測試新的 Service Worker 程式碼,而不必手動取消註冊 Service Worker。
瞭解詳情
Service Worker 可做為網路應用程式與網路之間的 Proxy。
讓我們新增擷取事件監聽器,攔截來自網域的要求。
在 service-worker.js 加入以下程式碼:
self.addEventListener('fetch', event => {
console.log('Fetching:', event.request.url);
});儲存指令碼並重新整理頁面,即可安裝及啟用更新後的 Service Worker。
檢查控制台,並觀察是否記錄任何擷取事件。重新整理頁面,然後再次檢查控制台。這次您應該會看到網頁及其資產 (例如 CSS) 的擷取事件。
按一下「Other page」(其他頁面)、「Another page」(另一個頁面) 和「Back」(返回) 連結。
您會在每個網頁及其資產的控制台中看到擷取事件。所有記錄是否合理?
注意:如果造訪頁面時未停用 HTTP 快取,CSS 和 JavaScript 資產可能會在本機快取。如果發生這種情況,您就不會看到這些資源的擷取事件。
說明
瀏覽器在服務工作人員範圍內發出的每個 HTTP 要求,都會觸發擷取事件,並傳送給服務工作人員。擷取事件物件包含要求。在 Service Worker 中監聽擷取事件,與在 DOM 中監聽點擊事件類似。在我們的程式碼中,當擷取事件發生時,我們會將要求的網址記錄到控制台中 (實際上,我們也可以建立並傳回自己的自訂回應,其中包含任意資源)。
為什麼第一次重新整理時,系統沒有記錄任何擷取事件?根據預設,除非網頁要求本身經過 Service Worker,否則網頁的擷取事件不會經過 Service Worker。這可確保網站的一致性;如果網頁載入時沒有 Service Worker,其子資源也會一併載入。
瞭解詳情
解決方案程式碼
如要取得有效程式碼副本,請前往 04-intercepting-network-requests/ 資料夾。
Service Worker 有範圍。服務工作站的範圍決定了服務工作站攔截要求的路徑。
尋找範圍
將 index.html 中的註冊程式碼更新為:
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('service-worker.js')
.then(registration => {
console.log('SW registered with scope:', registration.scope);
})
.catch(err => {
console.error('Registration failed:', err);
});
});
}重新整理瀏覽器。請注意,控制台會顯示 Service Worker 的範圍 (在本例中為 http://localhost:8081/)。
說明
register() 傳回的 Promise 會解析為註冊物件,其中包含 Service Worker 的範圍。
預設範圍是服務工作站檔案的路徑,並延伸至所有下層目錄。因此,應用程式根目錄中的服務工作人員會控管應用程式中所有檔案的要求。
移動 Service Worker
將 service-worker.js 移至 below/ 目錄,並更新 index.html 註冊程式碼中的服務工作人員網址。
在瀏覽器中取消註冊目前的 Service Worker,然後重新整理頁面。
控制台會顯示服務工作人員的範圍現在為 http://localhost:8081/below/。在 Chrome 中,您也可以在開發人員工具的「應用程式」分頁中查看 Service Worker 範圍:

返回主頁面,依序點按「Other page」、「Another page」和「Back」。系統會記錄哪些擷取要求?哪些不是?
說明
服務工作站的預設範圍是服務工作站檔案的路徑。由於服務工作人員檔案現在位於 below/,因此這是檔案的範圍。現在控制台只會記錄 another.html、another.css 和 another.js 的擷取事件,因為這些是 Service Worker 範圍內的唯一資源。
設定任意範圍
將 Service Worker 移回專案根目錄 (app/),並更新 index.html 註冊程式碼中的 Service Worker 網址。
使用 MDN 上的參照,透過 register() 中的選用參數,將服務工作站的範圍設為 below/ 目錄。
取消註冊 Service Worker,然後重新整理頁面。按一下「其他頁面」、「其他頁面」和「返回」。
控制台再次顯示服務工作人員的範圍現在是 http://localhost:8081/below/,且只會記錄 another.html、another.css 和 another.js 的擷取事件。
說明
您可以在註冊時傳遞額外參數,設定任意範圍,例如:
navigator.serviceWorker.register('/service-worker.js', {
scope: '/kitten/'
});在上述範例中,服務工作人員的範圍設為 /kitten/。Service Worker 會攔截 /kitten/ 和 /kitten/lower/ 中網頁的要求,但不會攔截 /kitten 或 / 等網頁的要求。
注意:您無法設定高於 Service Worker 實際位置的任意範圍。不過,如果伺服器工作人員在以 Service-Worker-Allowed 標頭放送的用戶端上處於啟用狀態,您可以在服務工作人員的位置上方,為該服務工作人員指定最大範圍。
瞭解詳情
解決方案程式碼
如要取得有效程式碼副本,請前往 solution/ 資料夾。
您現在已啟動並執行簡單的 Service Worker,也瞭解 Service Worker 的生命週期。
瞭解詳情
如要查看 PWA 訓練課程中的所有程式碼研究室,請參閱課程的歡迎程式碼研究室。