標籤:

用人話來講解一下 Service Worker 和 PWA

標題上為啥要把PWA放在Service Worker後面?因為要理解和開發PWA,Service Worker是決定性因素,為啥這麼說,往下看便知曉。

不想因為用戶體驗而丟失用戶,你必須會用Service Worker!--- 致前端開發的小夥伴們

先說一下PWA是個什麼鬼,它身份證上的名字是Progressive Web App,看名字就瞬間秒懂了,它就是個網頁,只不過做了一些改進,試圖搶佔APP的市場份額。

針對我們日常使用的APP(美團、餓了么等)來說,除了消息推送以外,APP上的所有功能在網頁上都能實現。但是你可能忽略了很關鍵的一點,就是在沒有網的情況下,APP還能正常打開,但是網頁呢,你只能打開一個提示無法連接的頁面,可你要說了,APP即便能打開又怎麼樣,沒網還是用不了啊,但你別忘了,有些APP運行是不需要網的,比如計算器,沒網APP照樣用,可如果做個網頁版的計算器,沒網可就完犢子了!所以,網頁和APP能否一較高下,需要解決的關鍵問題就是「沒有網你咋辦?」,Service Worker的出現就是來解決這個問題的,也正是因為有了Service Worker,PWA才敢和APP叫板。

簡單介紹一下Service Worker,它實際上就是瀏覽器提供的一組JavaScript API,這組API的功能肯定是相當豐富了,但是咱得撈乾的說,對咱們最重要的功能就兩個,一個是對網頁及其資源的離線緩存,另一個是對瀏覽器請求的攔截。

說到這你可能明白了,要實現網頁在沒有網的情況下還能用,對網頁做離線緩存就可以了,HTML5早就有這個功能,你說的應該是AppCache吧,這貨雖然可以達到緩存的目的,但是本質上來講,它和你在瀏覽器上選擇菜單里的「網頁另存為」,把網頁保存到本地,沒啥太大區別。這就意味著,如果你想清除緩存,sorry,作為程序員的你,辦不到,辦不到,辦不到!你還得勞駕用戶自己通過操作瀏覽器的方式清除緩存。要知道,人家APP對於緩存的操作可是想咋整就咋整,網頁想跟APP懟,就憑AppCache這麼個玩意,肯定拿不出手啊!所以下面咱們就來看看Service Worker是怎麼做離線緩存的。

我們知道JavaScript是單線程運行的,可是瀏覽器這次史無前例的為了Service Worker單獨開了一個線程,也就是說當瀏覽器載入你的網頁的時候,網頁上的腳本運行在一個線程中,而Service Worker自己運行在另一個線程中,他們互不干涉內政,你不用擔心Service Worker會影響你原本的網頁載入效果,所以,你應該能夠想到,我們必須把Service Worker的代碼單獨放在一個js文件中,我們通常會建立一個service-worker.js文件,那麼這個文件是怎麼和你的網頁搞到一起的呢,注意,現在需要在你的網頁中寫代碼了

//這裡是要檢查用戶的瀏覽器是否支持Service Worker//從這裡就可以看出Service Worker就是navigator的一個屬性對象if (serviceWorker in navigator) { //添加一個網頁載入事件的監聽器 window.addEventListener(load, function () { //當網頁載入完成後,把service-worker.js文件註冊到網頁中 navigator.serviceWorker.register(/service-worker.js) });}

上面代碼執行完以後,Service Worker就和你的網頁息息相關了,他會一直為你的網頁服務,直到它被卸載為止,其實代碼還是非常簡單的,但是說了這麼多,代碼也寫了,還是沒說Service Worker是怎麼做緩存的啊,你要注意,上面代碼是在你的網頁中的,並不是在service-worker.js文件里的,這個代碼的作用只是把service-worker.js註冊到你的網頁上,讓他起作用,所以,真正實現緩存功能的代碼肯定在service-worker.js文件里啦!那麼這裡的代碼應該怎麼寫呢?

可以想像這裡的代碼一定很多很複雜,但是我要恭喜你的是,這裡的代碼根本就,不用寫,不用寫,不用寫!因為我們有工具來生成它,他就是,噹噹噹噹,sw-precache,它身份證上的名字是Service Worker Precache,其實上面寫在你網頁里的代碼也是可以自動生成的,但是需要你會用webpack,考慮到你可能還不了解webpack,我們就不提這鬧心的事了,幸好sw-precache還有命令行下的使用方式。

sw-precache這貨實際上是個nodejs模塊,所以要使用它你還得先把nodejs安裝好,至於怎麼安裝nodejs,等nodejs社區倒閉了我再告訴你。下面說怎麼安裝sw-precache,在命令行下運行如下命令:

npm install --global sw-precache (別忘了回車啊)

根據我的經驗,你的安裝過程中不會出現任何問題,簡單的說一下--global這個參數是啥意思,它是告訴nodejs這個模塊要進行全局安裝,這就意味著你在系統的任何目錄下都可以執行sw-precache的命令了,所以,現在你就可以在你的web伺服器上創建一個網站,把我提供給你的 demo 文件放在網站目錄下,打開命令行cd到網站目錄,執行下面命令:

sw-precache (我再告訴你,別忘了回車啊)

這時在當前目錄會生成一個service-worker.js文件,沒錯,這就是我們想要的,一切都搞定了!現在打開瀏覽器(別說我沒提醒你用Chrome,用別的瀏覽器行不行以後再說),訪問你的這個網站,然後你肯定迫不及待的要測試一下沒網它還能不能正常打開,OK,但是你可別去斷開網路連接啊(我估計你不會傻到這份上),因為你訪問的是本機地址(例如:http://localhost),沒網也照樣能訪問,所以你應該做的是關閉你的web伺服器,然後你再去刷新Chrome(狂按F5吧),怎麼樣?

咱們說了,Service Worker是在獨立線程中運行的,那是不是可以觀測一下它運行的咋樣啊?必須的!打開下面這個URL

chrome://inspect/#service-workers

這時你可以看到當前正在運行的Service Worker線程,如果你想看的更詳細一點,就打開這個URL

chrome://serviceworker-internals

這時連沒運行的Service Worker線程也能看到了,並且還有各種屬性,而且如果你看哪個Service Worker線程不順眼還可以把它卸載了(Unregister)。

你可能覺得這似乎有點太簡單了,這樣就實現了離線緩存嗎?是的,當執行sw-precache命令的時候,它默認把當前目錄下的所有文件都進行緩存,並且加上緩存邏輯形成了一個service-worker.js文件。但有時候我們並不想緩存所有文件,只想緩存指定目錄下的文件,那你可以給sw-precache提供一個配置文件來實現:

// sw-precache-config.jsmodule.exports = { staticFileGlobs: [ //指定要進行靜態緩存的文件 app/css/**.css, //緩存所有css文件,以下的配置語法都類似 app/**.html, app/images/**.*, app/js/**.js ], runtimeCaching: [{ urlPattern: /index\.php/, }]}

然後執行下面的命令:

sw-precache --config=sw-precache-config.js --verbose

上面的配置文件有一個配置節點你一定會感興趣,runtimeCaching,這個節點是用來配置動態緩存的,靜態緩存和動態緩存的區別是:靜態緩存意思就是在網頁載入的時候就明確的告訴瀏覽器需要緩存什麼文件,而動態緩存的意思是,在網頁載入之前我們還不能確定哪些文件需要緩存,我們要在網頁的運行期通過程序來判斷哪些要緩存哪些不緩存。開頭咱們說了,原生APP對於緩存可是想咋整就咋整,現在有了動態緩存,咱網頁APP就真的能和原生APP磕了,還記得咱們說Service Worker有兩個對咱們最重要的功能嗎?一個是離線緩存,一個是請求攔截,這個動態緩存就是通過請求攔截來實現的。

以上這些都只是雕蟲小技,如果Service Worker只能幹這些事就太名不符實了,它還有一個功能說出來嚇死你,它能給用戶推送消息通知,不信嗎?你用沒用過網頁版的微信啊?如果你是第一次打開網頁版微信,會出現一個提示框,問是否允許微信給你發送通知,如果你點擊允許了,以後微信有消息,就會在右下角彈出消息通知。呵呵,老鐵們,有了這個功能,咱WebAPP和原生APP還差啥?

說到這吧,下次咱們具體來說說動態緩存!


推薦閱讀:

蘋果官方對PWA支持步伐奇快, iOS 11.3 和 macOS 10.13.4 將默認支持Service Worker
阿里雲前端周刊 - 第 39 期
Progressive Web Apps - Part.2 PWA 是什麼?

TAG:PWA |