PWA筆記二:離線緩存原理

ServiceWorker既然命名為worker华弓,很大一部分原因就是它和WebWorker相關(guān)网梢。它是在第二個(gè)線程完成緩存代理的任務(wù)履澳,不會(huì)影響dom渲染的主線程竖哩,兩個(gè)Worker之間的通訊是基于postMessage哭廉,兩個(gè)線程是不能直接進(jìn)行通訊。

這一點(diǎn)和小程序有點(diǎn)像相叁,但是又不一樣遵绰。 小程序是把渲染層和邏輯層用兩個(gè)線程進(jìn)行分離。邏輯層的報(bào)錯(cuò)增淹,并不會(huì)影響渲染層的展示椿访,具體這么做能夠提升多少優(yōu)化量,微信團(tuán)隊(duì)并沒有給出一個(gè)很確切的數(shù)據(jù)統(tǒng)計(jì)虑润。PWA使用worker更多是為了處理離線緩存的內(nèi)容成玫,并且會(huì)使用indexedDB來存緩存文件的版本編號(hào),UI的渲染層和邏輯層(可以被稱之為主線層)并沒有得到分離拳喻。

前提條件

基于HTTPS

HTTPS 不僅僅可以保證你網(wǎng)頁的安全性哭当,還可以讓一些比較敏感的 API 完美的使用。值得一提的是冗澈,SW 是基于 HTTPS 的钦勘,所以,如果你的網(wǎng)站不是 HTTPS亚亲,那么基本上你也別想了 SW彻采。

Scope作用域

一個(gè)sw.js并不能接管一個(gè)站點(diǎn)所有的頁面,它只能在所在路由底下起到作用捌归。意思就是如果你在//example.com/foo/bar.js里注冊(cè)了一個(gè) SW肛响,那么它默認(rèn)的作用域?yàn)?code>//example.com/foo/。

SPA

雖然說PWA可以使用在多頁面應(yīng)用(MPA)上惜索,一個(gè)sw文件和一個(gè)manifest文件主要的設(shè)計(jì)理念在于搭配著用在SPA特笋,SW在SPA使用更合理。

生命周期

注冊(cè)

ServiceWorker.js(又名sw.js)是一個(gè)獨(dú)立js门扇,頁面注冊(cè)在瀏覽器支持的情況下雹有,注冊(cè)sw.js來控制Service Worker緩存偿渡。register將會(huì)觸發(fā)安裝聲明周期臼寄,所有的源碼都是有原生瀏覽器實(shí)現(xiàn)霸奕。

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').then(function(registration) {
    console.log('ServiceWorker registration successful with scope: ',    registration.scope);
  }).catch(function(err) {
    console.log('ServiceWorker registration failed: ', err);
  });
}

install

注冊(cè)完成后會(huì)出發(fā)安裝的生命周期,把設(shè)置好的靜態(tài)文件吉拳,采用Service Worker的緩存方式,使用了Cache API來將資源緩存起來,同時(shí)使用e.waitUntil接手一個(gè)Promise來等待資源緩存成功斗蒋,等到這個(gè)Promise狀態(tài)成功后爷肝,ServiceWorker進(jìn)入installed狀態(tài),意味著安裝完畢炼邀。這時(shí)候主線程中返回的registration.waiting屬性代表進(jìn)入installed狀態(tài)的ServiceWorker魄揉。

var CACHE_NAME = "my_cache";
var urlsToCache = [
  '/index.html',
  '/css/style.css',
  '/js/script.js'
];
//這里的self代表ServiceWorkerGlobalScope
self.addEventListener('install', function(event) {
//這里的waitUtil會(huì)在安裝成功之前執(zhí)行一些預(yù)裝的操作,但是只建議做一些輕量級(jí)和非常重要資源的緩存拭宁,減少安裝失敗的概率洛退。安裝成功
//后ServiceWorker狀態(tài)會(huì)從installing變?yōu)閕nstalled 
event.waitUntil(
        caches.open(CACHE_NAME).then(function(cache) {
             console.log('Opendhe : ',cache);
            return cache.addAll(urlsToCache);
      })
    );
});

skipWaiting

skipWaiting()意味著新 SW 控制了之前用舊 SW 獲取的頁面,也就是說你的頁面有一部分資源是通過舊 SW 獲取杰标,剩下一部分是通過新 SW 獲取.

activate

安裝完兵怯,則會(huì)進(jìn)入激活狀態(tài)。如果之前已有ServiceWorker腔剂,這個(gè)版本只是對(duì)ServiceWorker進(jìn)行了更新媒区。如果你在event.waitUntil()中傳入了一個(gè) Promise,SW 將會(huì)緩存住功能性事件(fetch,push,sync等等)掸犬,直到 Promise 返回 resolve 的時(shí)候再觸發(fā)袜漩,也就是說,當(dāng)你的fetch事件被觸發(fā)的時(shí)候湾碎,SW 已經(jīng)被完全激活了噪服。

self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(keys => Promise.all(
      keys.map(key => {
        if (!expectedCaches.includes(key)) {
          return caches.delete(key);
        }
      })
    )).then(() => {
      // V2控制緩存
    })
  );
});

fetch

fetch請(qǐng)求是有別于xhr請(qǐng)求,sw提供監(jiān)聽攔截fetch的事件胜茧,對(duì)于命中緩存的數(shù)據(jù)可以直接返回請(qǐng)求粘优。當(dāng)接受到 fetch 請(qǐng)求時(shí),會(huì)直接返回event.respondWith 得到Promise 結(jié)果呻顽。這樣我們可以捕獲頁面所有的 fetch 請(qǐng)求雹顺。

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Cache hit - return response
        if (response) {
          return response;
        }
        return fetch(event.request);
      }
    )
  );
});

redundant

Service Worker 可能以下之一的原因而被廢棄(redundant,原意為“多余的廊遍,累贅的”)——

  • installing 事件失敗
  • activating 事件失敗
  • 新的 Service Worker 替換其成為激活態(tài) worker

調(diào)試方法

方法一

chrome://inspect/#service-workers 就可以查看當(dāng)前瀏覽器正在注冊(cè)的 SW嬉愧,并且可以對(duì)它們進(jìn)行調(diào)試和結(jié)束進(jìn)程。調(diào)試會(huì)直接在service worker線程進(jìn)行喉前,不用理會(huì)主線層的邏輯没酣。

調(diào)試Service worker

方法二

另外王财,還有 chrome://serviceworker-internals,用來查看當(dāng)前瀏覽器中所有注冊(cè)過的 SW裕便。輸入這個(gè)地址就像打開新世界的大門绒净,原來你訪問那么多PWA頁面。

所有注冊(cè)過的service worker

方法三

在打開chrome的調(diào)試面板devtools偿衰,Application tab里面有個(gè)service workers頁面挂疆,可以針對(duì)該頁面的SW,進(jìn)行緩存調(diào)試以及消息推送下翎,在這里也可以看到SW所在的生命周期缤言,大大提高SW的調(diào)試效率。

chrome查看緩存情況

更新問題

瀏覽器獲取了新版本的ServiceWorker代碼视事,如果瀏覽器本身對(duì)sw.js進(jìn)行緩存的話胆萧,也不會(huì)得到最新代碼,所有代碼會(huì)變成死代碼無法更新俐东。這里有兩種解決方案:

  1. 在ngnix或cdn的緩存配置中跌穗,sw文件最好配置成cache-control: no-cache
  2. 采用sw-register-webpack-plugin來處理sw文件的更新問題犬性。

參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瞻离,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子乒裆,更是在濱河造成了極大的恐慌套利,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鹤耍,死亡現(xiàn)場離奇詭異肉迫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)稿黄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門喊衫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人杆怕,你說我怎么就攤上這事族购。” “怎么了陵珍?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵寝杖,是天一觀的道長。 經(jīng)常有香客問我互纯,道長瑟幕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮只盹,結(jié)果婚禮上辣往,老公的妹妹穿的比我還像新娘。我一直安慰自己殖卑,他們只是感情好站削,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著懦鼠,像睡著了一般钻哩。 火紅的嫁衣襯著肌膚如雪屹堰。 梳的紋絲不亂的頭發(fā)上肛冶,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音扯键,去河邊找鬼睦袖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛荣刑,可吹牛的內(nèi)容都是我干的馅笙。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼厉亏,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼董习!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起爱只,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤皿淋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后恬试,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窝趣,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年训柴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了哑舒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡幻馁,死狀恐怖洗鸵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情仗嗦,我是刑警寧澤膘滨,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站儒将,受9級(jí)特大地震影響吏祸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一贡翘、第九天 我趴在偏房一處隱蔽的房頂上張望蹈矮。 院中可真熱鬧,春花似錦鸣驱、人聲如沸泛鸟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽北滥。三九已至,卻和暖如春闸翅,著一層夾襖步出監(jiān)牢的瞬間再芋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來泰國打工坚冀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留济赎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓记某,卻偏偏與公主長得像司训,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子液南,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345