Service Worker 註冊

服務工作者註冊時機的最佳做法。

服務工作者可大幅加快使用者重複造訪您的網頁應用程式,但您應採取措施,確保服務工作者的初始安裝作業不會降低使用者的首次造訪體驗。

一般來說,延後服務工作者註冊,等到初始網頁載入後再註冊,可為使用者提供最佳體驗,尤其是網路連線速度較慢的行動裝置使用者。

常見的註冊程式碼

如果您曾閱讀服務工作者相關說明,可能會看到類似以下的樣板:

if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service-worker.js');
}

這可能會伴隨一些 console.log() 陳述式,或是用於偵測先前 Service Worker 註冊項目更新的程式碼,以便通知使用者重新整理網頁。但這些只是標準幾行程式碼的細微差異

那麼,「navigator.serviceWorker.register」是否有任何細微差異?是否有任何最佳做法可供參考?不出所料 (考量到本文並未就此結束),兩者的答案都是「是」

使用者初次造訪

請想想使用者第一次造訪網頁應用程式時的情況。此時還沒有服務工作者,瀏覽器無法事先得知是否會最終安裝服務工作者。

開發人員的首要任務,應是確保瀏覽器能快速取得顯示互動式頁面所需的必要資源最小集合。任何拖慢擷取這些回應的速度,都是為了提供快速的互動體驗。

假設在下載網頁需要轉譯的 JavaScript 或圖片時,瀏覽器決定啟動背景執行緒或程序 (為了簡潔起見,我們假設這是執行緒)。假設您並未使用效能強大的桌上型電腦,而是許多人視為主要裝置的效能不足的手機。啟動這個額外的執行緒會增加 CPU 作業時間和記憶體的爭用情形,而瀏覽器也可能耗費在轉譯互動式網頁時才會耗用資源。

閒置的背景執行緒不太可能產生顯著差異。但如果該執行緒並非閒置,而是決定也要開始從網路下載資源,該怎麼辦?與 CPU 或記憶體競爭的疑慮,應退居次要,因為許多行動裝置的頻寬有限。頻寬資源非常寶貴,因此請勿同時下載次要資源,以免影響重要資源。

這一切都是為了說明,如果您要讓使用者首次造訪網站時,能以最短的時間提供互動體驗,那麼啟動新的服務工作者執行緒,在背景下載及快取資源,可能會與此目標背道而行。

改善樣板

解決方案是選擇呼叫 navigator.serviceWorker.register() 的時間,藉此控制服務 worker 的啟動時間。簡單的經驗法則是延後註冊,直到 load eventwindow 上觸發為止,如下所示:

if ('serviceWorker' in navigator) {
    window.addEventListener('load', function() {
    navigator.serviceWorker.register('/service-worker.js');
    });
}

不過,啟動服務工作者註冊的適當時間也取決於網路應用程式在載入後執行的動作。舉例來說,Google I/O 2016 網頁版應用程式會在轉換至主畫面前顯示短動畫。我們的團隊發現,如果在動畫期間啟動 Service Worker 註冊作業,可能會導致低階行動裝置發生卡頓。為了避免使用者體驗不佳,我們延後服務工作者註冊作業,直到動畫結束後才執行,因為瀏覽器最有可能在動畫結束後有幾秒的閒置時間。

同樣地,如果您的網頁應用程式使用的架構會在頁面載入後執行其他設定,請找出在作業完成時告知的架構專屬事件。

後續造訪

我們一直以來都著重於初次造訪體驗,但延遲註冊服務工作者會對網站的多次造訪體驗產生什麼影響?雖然這可能讓某些人感到意外,但應該不會有任何影響。

註冊服務工作處理程序後,系統會執行 installactivate 生命週期事件。服務工作者啟用後,即可處理任何後續對網路應用程式造訪的 fetch 事件。服務工作者會在啟動其範圍內任何網頁的請求,這點很合理。如果現有的 Service Worker 在造訪網頁前並未執行,就無法針對導覽要求完成 fetch 事件。

因此,一旦有服務 worker 在運作,您何時呼叫 navigator.serviceWorker.register() 或是否呼叫 navigator.serviceWorker.register() 都無所謂。您是否呼叫 navigator.serviceWorker.register()也無所謂。除非您變更 Service Worker 指令碼的網址,否則在後續造訪期間,navigator.serviceWorker.register() 實際上是免人工管理。呼叫的圖片不相關

盡早註冊的好處

是否有盡可能盡早註冊 Service Worker 的情境?提醒您,在首次造訪時,Service Worker 會使用 clients.claim() 控管頁面,而 Service Worker 會在其 fetch 處理常式內積極執行執行階段快取。在這種情況下,盡快讓服務工作者生效會帶來好處,因為這樣就能嘗試在執行階段快取中填入日後可能派上用場的資源。如果您的網路應用程式屬於這個類別,建議您先退一步,確保服務工作站的 install 處理常式不會要求與主頁面要求爭奪頻寬的資源。

測試新功能

如要模擬首次造訪,建議您在 Chrome 無痕式視窗中開啟網頁應用程式,然後在 Chrome 的 DevTools 中查看網路流量。身為網頁開發人員,您可能每天都會重新載入網頁應用程式的本機執行個體數十次。不過,如果在已存在服務工作者且快取已完全填入的情況下重新造訪網站,您將無法獲得新使用者所獲得的體驗,而且很容易忽略潛在問題。

以下舉例說明註冊時間可能產生的差異。這兩張螢幕截圖都是在無痕模式下,使用網路節流功能模擬連線速度緩慢的情況,查看範例應用程式時擷取。

網路流量 (含早期註冊)。

以上螢幕截圖反映了修改範例以盡快執行 Service Worker 註冊時的網路流量。您可以看到預先快取要求 (其旁邊的「齒輪」圖示相關項目,源自服務工作站的 install 處理常式) 與顯示頁面所需的其他資源的要求交錯顯示。

網路流量,其中包含延遲註冊。

在上方螢幕截圖中,Service Worker 的登錄作業會延遲到頁面載入後才進行。您可以看到系統從網路擷取了所有資源後,才會啟動預先快取要求,藉此消除頻寬爭用情形。此外,由於我們預先快取的部分項目已在瀏覽器的 HTTP 快取中 (在「Size」欄中顯示 (from disk cache) 的項目),因此我們可以填入服務工作者的快取,而無須再次連線。

如果你是在實際行動網路上透過實際的低階裝置執行這類測試,可以額外獲得點數。您可以利用 Chrome 的遠端偵錯功能,透過 USB 將 Android 手機連接到電腦,確保您執行的測試能反映許多使用者的實際體驗。

結論

總而言之,確保使用者在首次造訪時能獲得最佳體驗,應是首要之務。在初次造訪期間延後服務工作者註冊,等網頁載入完畢後再註冊,有助於確保這項功能。您仍可享有使用服務工作站的所有好處,包括重複造訪時的效能提升。

如要確保服務工作者的初始註冊作業會延後至第一個網頁載入後才執行,最簡單的方法就是使用以下方法:

if ('serviceWorker' in navigator) {
    window.addEventListener('load', function() {
    navigator.serviceWorker.register('/service-worker.js');
    });
}