當下PWA比較火,而Service Worker是實現PWA的一項關鍵技術,今天咱們一塊兒瞭解下關於Service Worker的一些基礎知識和適用場景。web
咱們先來看一下官方文檔中對於Server Worker的核心定義:chrome
Service workers 本質上充當Web應用程序與瀏覽器之間的代理服務器,也能夠在網絡可用時做爲瀏覽器和網絡間的代理。
這是一條很準確的定義,但對於不瞭解Service Worker的同窗來講可能並不形象,下面咱們更形象的理解一下這個概念。咱們以去銀行取錢爲例子,其過程大概以下圖:瀏覽器
從上面的圖中咱們能夠看到,銀行的錢存在金庫中,客戶取錢時並非直接去金庫裏拿,而是須要經過銀行的工做人員,再告知銀行工做人員須要多少錢,並出示相應憑證後,由銀行工做人員從金庫中拿出錢給客戶,並從帳戶中減去相應金額。這麼作的緣由很容易理解,由於金庫是公用的,全部客戶的錢都放在裏面,咱們沒法保證每一個客戶都能只拿走屬於本身的錢,並按照實際狀況更新金庫記錄。緩存
咱們的應用在請求服務器資源時,其過程也是相似的:服務器
從上面的圖能夠看到,請求資源的過程當中,HTTP協議充當了取錢過程當中的銀行工做人員,客戶端應用須要的資源在服務器上,但應用卻沒法直接去服務器獲取資源,而是經過HTTP協議進行,請求中指定的各類Header信息,就是取錢時的憑證。網絡
而Service Worker能夠理解成,在客戶端建立了一個屬於本身的金庫,先看圖:工具
當咱們須要取錢或者獲取資源時,能夠先從本地的金庫中拿,本地金庫沒有,再經過原來的流程獲取。這時咱們再回頭看文章開始的定義,應該就可以理解了。優化
正常狀況下,客戶端獲取一個資源的過程有以下三步:this
而關於請求資源的優化,通常也集中在這三步完成:spa
看完上面的部分咱們能夠發現,當使用Service Worker中已有的資源時,客戶端應用獲取資源並無進入HTTP請求的流程,也就是說,經過Service Worker,客戶端應用能夠在不發出請求的狀況下得到資源,這很容易就讓咱們想到緩存,那麼Service Worker和咱們平時常常提到的強緩存和協商緩存等是什麼關係呢?整理了一個圖,能夠先看下:
從總體上來講,應用獲取一個資源的緩存類型分爲上圖中的四種,分別是Service Worker、Memory Cache、Disk Cache和No Cache。資源查找順序爲從左向右,找到資源則返回,未找到則繼續尋找,直至最終獲取資源。上面的圖中能夠清楚的看出Service Worker在緩存類型中的位置,也能看到跟平時常常提到的強緩存和協商緩存的關係。
在瞭解了Service Worker的概念後,咱們看下Servise Worker的基本使用邏輯,使用它的基礎過程是首先註冊一個Woker,這時瀏覽器會在後臺啓動一個新的線程,在這個線程啓動後,會按照Service Worker中的代碼邏輯將一些資源緩存下來,緩存完畢後,啓動對頁面請求的監聽,當監聽到頁面請求資源時能夠作出相對應的響應,好比若是資源在Service Worker中緩存過了,就能夠直接返回資源。
Service Worker對象保存在window.navigator內,首先調用register方法進行註冊,導入一個js文件,文件中是咱們的Service Worker邏輯,代碼以下:
navigator.serviceWorker.register('/sw.js') .then(function(reg){ console.log("success", reg); }).catch(function(err) { console.log("error", err); });
須要注意的是Service Worker是有做用域的,它的做用域爲文件的當前路徑,Service Worker文件只能管理本身做用下的資源,好比abcde.com/home/sw.js 的做用域爲abcde.com/home/。
註冊後的Service Worker就能在調試工具中看到了,下面是一個chrome調試面板的截圖:
畫紅框的內容是一些比較關鍵的信息,好比其中代表了Service Worker的文件名和路徑,以及當前Service Worker的狀態,Service Worker的狀態分爲幾種,STOPPED(已中止)、STARTING(正在啓動)、RUNNING(正在運行)和STOPPING(正在中止),好比上面的截圖就處於RUNNING狀態。
只有處於running狀態的Service Worker才能生效,這就須要對註冊後的Service Worker進行加載和激活,註冊完畢後,Service Worker會自動開始下載,下載後會觸發install事件,咱們能夠監聽這個事件並進行下載資源的操做,代碼以下:
const CACHE_NAME = "demo-a"; this.addEventListener("install", function(event) { console.log("install service worker success"); caches.open(CACHE_NAME); let cacheResources = ["https://abcde.com/demo.js"]; event.waitUntil( caches.open(CACHE_NAME).then(cache => { cache.addAll(cacheResources); }) ); });
通過上面的代碼,demo.js文件就被咱們緩存下來了,下載完後Service Worker就會執行激活:
this.addEventListener("active", function(event) { console.log("service worker active success"); });
此時咱們經過開發者工具就能看到一個激活的Service Worker了,總體梳理一下大概是下面的過程:
須要注意的是,圖中灰色的部分是一個獨立的特殊線程,並非瀏覽器渲染頁面執行js的線程,所以使用Service Worker的過程當中無需擔憂會影響頁面的渲染。
咱們註冊了Service Worker後,還面臨着更新的問題,當咱們的業務迭代時必然要更新Service Worker,在咱們理解了它的整個註冊過程後,理解更新就很簡單了,直接上圖:
當應用加載時,會下載Service Worker文件,這是在瀏覽器中就會有兩個文件,一個是當前正在使用的Service Worker,一個是新下載的Service Worker,當新下載的文件下載完畢後,瀏覽器會對兩個文件進行Diff操做,若是發現文件沒有更新,則會丟棄掉新下載的Service Worker文件,若是發現有變化,則會加載新的Service Worker,但新加載的Service Worker會處於wating狀態,並不會實際發揮做用,只有當整個瀏覽器中對正在運行的Service Worker沒有依賴時,纔會將運行中的Service Worker拋棄,將新的Servier Worker置爲激活狀態。
咱們瞭解一些Service Worker的基礎知識,以及一些比較常見的使用場景,那麼目前Service Worker的兼容性如何呢,看下圖
目前主流的現代瀏覽器支持度仍是不錯的,可是到目前爲止全系列的IE瀏覽器均不支持Service Worker,並且有一點感覺很明顯,在查資料的過程當中,看了網上很多的博客,不一樣的博客上也有當時寫博客時的Service Worker支持度,能夠明顯感受到Service Worker的支持程度在快速提高,隨着支持度的提高,相信會有愈來愈多的開發者在項目中使用這項技術。
藉助Service Worker,真正讓PWA應用變得流行,也許就在不久的未來。