JavaScript 是如何工作的:Service Worker 的生命週期及使用場景

發表於2019-01-08

圖片描述

你可能已經知道,漸進式Web應用程式 只會越來越受歡迎,因為它們的目標是讓Web應用程式使用者體驗更流暢,建立類似於原生應用程式的體驗,而不是瀏覽器的外觀和感覺。

構建漸進式Web應用程式的主要要求之一是使其在網路和載入方面非常可靠——它應該在不確定或不存在的網路條件下可用。

在這篇文章中,將深入探討 Service Workers:它們是如何工作,你應該關心什麼。最後,還列出了 Service Workers 中的一些獨特優點在哪些場景下是值得我們使用的。

簡介

如果你還想了解更多 Service Workers 的知識,可以閱讀作者關於 Web Workers 的文章。

Service Worker是什麼

MDN 的介紹:

Service Worker 是一個瀏覽器背後執行的腳步,獨立於 web 頁面,為無需一個頁面或使用者互動的功能開啟了大門。今日,它包含了推送通知和背景非同步(push notifications and background sync)的功能。將來,Service Worker 將支援包括 periodic sync or geofencing 的功能。

基本上,Service Worker 是 Web Worker 的一個型別,更具體地說,它像 Shared Worker

  • Service Worker 在其自己的全域性上下文中執行
  • 它沒有繫結到特定的網頁
  • 它不能訪問到 DOM

這是一個令人興奮的 API 的原因是它允許你支援離線體驗,讓開發人員完全控制體驗。

Service Worker 的生命週期

Service Worker 的生命週期與 web 頁面完全分離。它包括以下幾個階段:

  • 下載
  • 安裝
  • 啟用

下載

這是瀏覽器下載包含 Service Worker 的 .js 檔案的時候。

安裝

要為 web 應用程式安裝 Service Worker,必須先註冊它,這可以在 JavaScript 程式碼中完成。註冊 Service Worker 後,它會提示瀏覽器在後臺啟動 Service Worker 安裝步驟。

通過註冊 Service Worker,你可以告訴瀏覽器你的 Service Worker 的 JavaScript 檔案的位置。看看下面的程式碼:

圖片描述

上例程式碼首先檢查當前環境中是否支援 Service Worker API。如果支援,則 /sw.js 這個 Service Worker 就被註冊了。

每次頁面載入時都可以呼叫 register() 方法,瀏覽器會判斷 Service Worker 是否已經註冊,根據註冊情況會對應的給出正確處理。

register() 方法的一個重要細節是 Service Worker 檔案的位置。在本例中,可以看到 Service Worker 檔案位於域的根目錄,這意味著 Service Worker 範圍將是這個域下的。換句話說,這個 Service Worker 將為這個域中的所有內容接收 fetch 事件。如果我們在 /example/sw.js 註冊 Service Worker 檔案,那麼 Service Worker 只會看到以 /example/ 開頭的頁面的 fetch 事件(例如 /example/page1//example/page2/)。

通常在安裝步驟中,你需要快取一些靜態資源。 如果所有檔案都快取成功,則 Service Worker 將被安裝。 如果任何檔案無法下載和快取,則安裝步驟將失敗,Service Worker 將不會啟用(即不會被安裝)。 如果發生這種情況,不要擔心,下次再試一次。 但是,這意味著如果它安裝,你知道你有這些靜態資源在快取中。

如果註冊需要在載入事件之後發生,這就解答了你“註冊是否需要在載入事件之後發生”的疑惑。這不是必要的,但絕對是推薦的。

為什麼?讓我們考慮使用者第一次訪問你的 Web 應用程式。目前還沒有 Service Worker,而且瀏覽器無法預先知道最終是否會安裝 Service Worker。如果安裝了 Service Worker,瀏覽器將需要為這個額外的執行緒花費額外的 CPU 和記憶體,否則瀏覽器將把這些額外的 CPU 和記憶體用於呈現 Web 頁面。

最重要的是,如果在頁面上安裝一個 Service Worker,就可能會有延遲載入和渲染的風險 —— 而不是儘快讓你的使用者可以使用該頁面。

注意,這種情況對第一次的訪問頁面時才會有。後續的頁面訪問不會受到 Service Worker 安裝的影響。一旦 Service Worker 在第一次訪問頁面時被啟用,它就可以處理載入/快取事件,以便後續訪問 Web 應用程式。這一切都是有意義的,因為它需要準備好處理受限的的網路連線。

啟用

安裝 Service Worker 之後,下一步將是啟用它,這是處理舊快取管理的好機會。

在啟用步驟之後,Service Worker 將控制所有屬於其範圍的頁面,儘管第一次註冊 Service Worker 的頁面將不會被控制,直到再次載入。

Service Worker 一旦掌控,它將處於以下兩種狀態之一:

  • 處理從網頁發出網路請求或訊息時發生的提取和訊息事件
  • Service Worker 將被終止以節省記憶體

Service Worker 生命週期如下:

圖片描述

Service Worker 安裝的內部機制

在頁面啟動註冊過程之後,看看 Service Worker 指令碼中發生了什麼,它通過向 Service Worker 例項新增事件監聽來處理 install 事件:

以下是處理安裝事件時需要採取的步驟:

  • 開啟一個快取
  • 快取我們的檔案
  • 確認是否快取了所有必需的資源

對於最基本的示例,你需要為安裝事件定義回撥並決定要快取哪些檔案。

下面是 Service Worker 簡單的一個內部安裝過程:

圖片描述

從上例程式碼可以得到:

呼叫了caches.open() 和我們想要的快取名稱, 之後呼叫 cache.addAll() 並傳入檔案陣列。 這是一個promise 鏈( caches.open() 和 cache.addAll() )。 event.waitUntil() 方法接受一個承諾,並使用它來知道安裝需要多長時間,以及它是否成功。

如果成功快取了所有檔案,那麼將安裝 Service Worker。如果其中的一個檔案下載失敗,那麼安裝步驟將失敗。這意味著需要小心在安裝步驟中決定要快取的檔案列表,定義一長串檔案將增加一個檔案可能無法快取的機會,導致你的 Service Worker 沒有得到安裝。

處理 install 事件完全是可選的,你可以避免它,在這種情況下,你不需要執行這裡的任何步驟。

執行時快取請求

安裝了 Service Worker 後,使用者導航到另一個頁面或重新整理所在的頁面,Service Worker 將收到 fetch 事件。下面是一個例子,演示如何返回快取的資源或執行一個新的請求,然後快取結果:

圖片描述

上述流程:

  • 在這裡我們定義了 fetch 事件,在 event.respondWith() 中,我們傳遞了一個來自 caches.match()promise。 此方法檢視請求,並查詢來自 Service Worker 建立的任何快取的任何快取結果。
  • 如果在快取中,響應內容就被恢復了。
  • 否則,將會執行 fetch。
  • 檢查狀態碼是不是 200,同時檢查響應型別是 basic,表明響應來自我們最初的請求。在這種情況下,不會快取對第三方資源的請求。
  • 響應被快取下來

如果通過檢查,克隆響應。這是因為響應是 Stream,所以只能消耗一次。既然要返回瀏覽器使用的響應,並將其傳遞給快取使用,就需要克隆它,以便可以一個傳送到瀏覽器,一個傳送到快取。

更新 Service Worker

當使用者訪問你的 Web 應用程式時,瀏覽器試圖重新下載包含 Service Worker 程式碼的 .js 檔案,這是在後臺完成的。

如果現在下載的 Service Worker 的檔案與當前 Service Worker 的檔案相比如果有一個位元組及以上的差異,瀏覽器將假設 Service Worker 檔案已改過,瀏覽器就會啟動新的 Service Worker。

新的 Service Worker 將啟動並且安裝事件將被移除。然而,在這一點上,舊的 Service Worker 仍在控制你的 web 應用的頁面,這意味著新的 Service Worker 將進入 waiting 狀態。

一旦你的 Web 應用程式當前開啟的頁面被關閉,舊的 Service Worker 將被瀏覽器殺死,新 Service Worker 接管了控制權,它的啟用事件將被激發

為什麼需要這些?為了避免 Web 應用程式的兩個版本同時在不同的 tab 上執行的問題——這在 Web 上是非常常見的,並且可能會產生非常嚴重的bug(例如,在瀏覽器中本地儲存資料時使用不同的模式)。

從快取中刪除資料

在啟用回撥中發生的一個常見任務是快取管理。你要在啟用回撥中這樣做的原因是,如果你要在安裝步驟中清除所有舊的快取,任何保留所有當前頁面的舊 Service Worker 將會突然停止服務來自該快取的檔案。

這裡提供了一個如何從快取中刪除一些不在白名單中的檔案的例子(在本例中,有 page-1、page-2 兩個實體):

圖片描述

要求 HTTPS 的原因

在構建 Web 應用程式時,通過 localhost 使用 Service Workers,但是一旦將其部署到生產環境中,就需要準備好 HTTPS( 這是使用HTTPS 的最後一個原因)。

使用 Service Worker,可以很容易被劫持連線並偽造響應。如果不使用 HTTPs,人的web應用程式就容易受到黑客的攻擊。

為了更安全,你需要在通過 HTTPS 提供的頁面上註冊 Service Worker,以便知道瀏覽器接收的 Service Worker 在通過網路傳輸時未被修改。

瀏覽器支援

瀏覽器對 Service Worker 的支援正在變得越來越好:

圖片描述

Service Workers 特性將越來越完善及強大

Service Workers 提供的一些獨特特性包括:

  • 推送通知 — 允許使用者選擇從網路應用程式及時更新。
  • 後臺同步 — 允許延遲操作,直到使用者具有穩定的連線。通過這種方式,可以確保使用者想傳送的任何內容實都可以傳送。
  • 定期同步(後續開放) — 提供管理定期後臺同步功能的 API。
  • Geofencing (後續開放) — 可以定義引數,也稱為圍繞感興趣領域的 geofences。當裝置通過geofence 時,Web 應用程式會收到一個通知,該通知允許根據使用者的地理位置提供更好的體驗。

原文:

https://blog.sessionstack.com…

程式碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug

你的點贊是我持續分享好東西的動力,歡迎點贊!

一個笨笨的碼農,我的世界只能終身學習!

更多內容請關注公眾號《大遷世界》!

相關文章