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 網頁版應用程式會在轉換至主畫面前顯示短動畫。我們的團隊發現,在動畫期間啟動服務 worker 註冊程序,可能會導致低階行動裝置出現卡頓現象。為了避免使用者體驗不佳,我們延後服務工作者註冊作業,直到動畫播放完畢後再執行,因為瀏覽器最有可能在動畫播放完畢後有幾秒的閒置時間。

同樣地,如果您的網頁應用程式使用架構,在網頁載入後執行其他設定,請尋找架構專屬事件,以便在該工作完成時發出信號。

後續造訪

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

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

因此,一旦有服務 worker 在運作,您何時呼叫 navigator.serviceWorker.register() 或是否呼叫 navigator.serviceWorker.register() 都無所謂。您是否呼叫 navigator.serviceWorker.register()也無所謂。除非您變更服務工作者指令碼的網址,否則 navigator.serviceWorker.register() 在後續造訪期間實際上是無操作。呼叫時間點無關緊要。

提早註冊的好處

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

測試

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

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

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

上方螢幕截圖反映了修改範例以盡快執行服務工作者註冊作業時的網路流量。您可以看到預先快取要求 (旁邊有齒輪圖示的項目,源自服務工作者的 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');
    });
}