隨著前端快速發(fā)展,應(yīng)用的性能已經(jīng)變得至關(guān)重要,關(guān)于這一點(diǎn)大佬做了很多統(tǒng)計(jì)。你可以去看看。
如何降低一個(gè)頁(yè)面的網(wǎng)絡(luò)請(qǐng)求成本從而縮短頁(yè)面加載資源的時(shí)間并降低用戶可感知的延時(shí)是非常重要的一部分。對(duì)于提升應(yīng)用的加載速度常用的手段有Http Cache、異步加載、304緩存、文件壓縮、CDN、CSS Sprite、開(kāi)啟GZIP等等。這些手段無(wú)非是在做一件事情,就是讓資源更快速的下載到瀏覽器端。但是除了這些方法,其實(shí)還有更加強(qiáng)大的Service Worker線程。
Service Worker與PWA的現(xiàn)狀
說(shuō)起service worker就不得不提起PWA了,service worker做為PWA的核心技術(shù)之一,多年來(lái)一直被Google大力推廣,這里簡(jiǎn)單介紹一下。
通俗來(lái)說(shuō),PWA就是漸進(jìn)式web應(yīng)用(Progressive Web App)。早在16年初,Google便提出PWA,希望提供更強(qiáng)大的web體驗(yàn),引導(dǎo)開(kāi)發(fā)者回歸開(kāi)放互聯(lián)網(wǎng)。它彌補(bǔ)了web對(duì)比Native App急缺的幾個(gè)能力,比如離線使用、后臺(tái)加載、添加到主屏和消息推送等,同時(shí)它還具備了小程序標(biāo)榜的“無(wú)需安裝、用完即走”的特性。
雖然PWA技術(shù)已經(jīng)被W3C列為標(biāo)準(zhǔn),但是其落地情況一直以來(lái)是很讓人失望的,始終受到蘋(píng)果的阻礙,最重要的原因在于PWA繞過(guò)Apple Store審核,直接推給用戶。如果普及,這將威脅到蘋(píng)果的平臺(tái)權(quán)威,也就意味著蘋(píng)果與開(kāi)發(fā)者的三七分成生意將會(huì)落空。
所以一直以來(lái)safrai不支持mainfest以及service worker這兩項(xiàng)關(guān)鍵技術(shù),即使在18年開(kāi)始支持了,但是對(duì)PWA的支持力度也遠(yuǎn)遠(yuǎn)低于安卓,具體體現(xiàn)在service worker緩存無(wú)法永久保存,以及service worker的API支持不夠完善,一個(gè)最明顯的不同在于安卓版本的PWA會(huì)保留你的登錄狀態(tài),并且會(huì)系統(tǒng)級(jí)推送消息。而在蘋(píng)果上,這兩點(diǎn)都做不到。也就是說(shuō),iPhone上的微博PWA,每次打開(kāi)都要重新登錄,而且不會(huì)收到任何推送信息。
另外由于某些不可描述的原因,在國(guó)內(nèi)無(wú)法使用Service Worker的推送功能,雖然國(guó)內(nèi)已經(jīng)有兩家公司做了service worker的瀏覽器推送,但是成熟度還有待調(diào)研。
由于目前各版本手機(jī)瀏覽器對(duì)service worker的支持度都不太相同,同一個(gè)接口也存在差異化還有待統(tǒng)一,之于我們來(lái)說(shuō),也只能用Service Worker做一做PC瀏覽器的緩存了。
Service Worker的由來(lái)
Service Worker(以下簡(jiǎn)稱sw)是基于WEB Worker而來(lái)的。
眾所周知,javaScript 是單線程的,隨著web業(yè)務(wù)的復(fù)雜化,開(kāi)發(fā)者逐漸在js中做了許多耗費(fèi)資源的運(yùn)算過(guò)程,這使得單線程的弊端更加凹顯。web worker正是基于此被創(chuàng)造出來(lái),它是脫離在主線程之外的,我們可以將復(fù)雜耗費(fèi)時(shí)間的事情交給web worker來(lái)做。但是web worker作為一個(gè)獨(dú)立的線程,他的功能應(yīng)當(dāng)不僅于此。sw便是在web worker的基礎(chǔ)上增加了離線緩存的能力。當(dāng)然在 Service Worker 之前也有在 HTML5 上做離線緩存的 API 叫 AppCache, 但是 AppCache 存在很多缺點(diǎn),你可以親自看看。
sw是由事件驅(qū)動(dòng)的,具有生命周期,可以攔截處理頁(yè)面的所有網(wǎng)絡(luò)請(qǐng)求(fetch),可以訪問(wèn)cache和indexDB,支持推送,并且可以讓開(kāi)發(fā)者自己控制管理緩存的內(nèi)容以及版本,為離線弱網(wǎng)環(huán)境下的 web 的運(yùn)行提供了可能,讓 web 在體驗(yàn)上更加貼近 native。換句話說(shuō)他可以把你應(yīng)用里的所有靜態(tài)動(dòng)態(tài)資源根據(jù)不同策略緩存起來(lái),在你下次打開(kāi)時(shí)不再需要去服務(wù)器請(qǐng)求,這樣一來(lái)就減少了網(wǎng)絡(luò)耗時(shí),使得web應(yīng)用可以秒開(kāi),并且在離線環(huán)境下也變得可用。做到這一切你只需要增加一個(gè)sw文件,不會(huì)對(duì)原有的代碼產(chǎn)生任何侵入,是不是很perfect?
Service Worker基本特征
無(wú)法操作DOM
只能使用HTTPS以及l(fā)ocalhost
可以攔截全站請(qǐng)求從而控制你的應(yīng)用
與主線程獨(dú)立不會(huì)被阻塞(不要再應(yīng)用加載時(shí)注冊(cè)sw)
完全異步,無(wú)法使用XHR和localStorage
一旦被 install,就永遠(yuǎn)存在,除非被 uninstall或者dev模式手動(dòng)刪除
獨(dú)立上下文
響應(yīng)推送
后臺(tái)同步
。。。
service worker是事件驅(qū)動(dòng)的worker,生命周期與頁(yè)面無(wú)關(guān)。 關(guān)聯(lián)頁(yè)面未關(guān)閉時(shí),它也可以退出,沒(méi)有關(guān)聯(lián)頁(yè)面時(shí),它也可以啟動(dòng)。
Dedicated Worker以及Shared Worker與Service Worker三者非常重要的區(qū)別在于不同的生命周期。對(duì)于Service Worker來(lái)說(shuō)文檔無(wú)關(guān)的生命周期,是它能提供可靠Web服務(wù)的一個(gè)重要基礎(chǔ)。
Service Worker生命周期
register 這個(gè)是由 client 端發(fā)起,注冊(cè)一個(gè) serviceWorker,這需要一個(gè)專門處理sw邏輯的文件
Parsed 注冊(cè)完成,解析成功,尚未安裝
installing 注冊(cè)中,此時(shí) sw 中會(huì)觸發(fā) install 事件, 需知 sw 中都是事件觸發(fā)的方式進(jìn)行的邏輯調(diào)用,如果事件里有 event.waitUntil() 則會(huì)等待傳入的 Promise 完成才會(huì)成功
installed(waiting) 注冊(cè)完成,但是頁(yè)面被舊的 Service Worker 腳本控制, 所以當(dāng)前的腳本尚未激活處于等待中,可以通過(guò) self.skipWaiting() 跳過(guò)等待。
activating 安裝后要等待激活,也就是 activated 事件,只要 register 成功后就會(huì)觸發(fā) install ,但不會(huì)立即觸發(fā) activated,如果事件里有 event.waitUntil() 則會(huì)等待這個(gè) Promise 完成才會(huì)成功,這時(shí)可以調(diào)用 Clients.claim() 接管所有頁(yè)面。
activated 在 activated 之后就可以開(kāi)始對(duì) client 的請(qǐng)求進(jìn)行攔截處理,sw 發(fā)起請(qǐng)求用的是 fetch api,XHR無(wú)法使用
fetch 激活以后開(kāi)始對(duì)網(wǎng)頁(yè)中發(fā)起的請(qǐng)求進(jìn)行攔截處理
terminate 這一步是瀏覽器自身的判斷處理,當(dāng) sw 長(zhǎng)時(shí)間不用之后,處于閑置狀態(tài),瀏覽器會(huì)把該 sw 暫停,直到再次使用
update 瀏覽器會(huì)自動(dòng)檢測(cè) sw 文件的更新,當(dāng)有更新時(shí)會(huì)下載并 install,但頁(yè)面中還是老的 sw 在控制,只有當(dāng)用戶新開(kāi)窗口后新的 sw 才能激活控制頁(yè)面
redundant 安裝失敗, 或者激活失敗, 或者被新的 Service Worker 替代掉
Service Worker 腳本最常用的功能是截獲請(qǐng)求和緩存資源文件, 這些行為可以綁定在下面這些事件上:
install 事件中, 抓取資源進(jìn)行緩存
activate 事件中, 遍歷緩存, 清除過(guò)期的資源
fetch 事件中, 攔截請(qǐng)求, 查詢緩存或者網(wǎng)絡(luò), 返回請(qǐng)求的資源