Service Workers簡(jiǎn)介(二)

——evilrescuer翻譯自Matt Gaunt
寫(xiě)的[Service Workers: an Introduction](收錄于 谷歌開(kāi)發(fā)者)(https://developers.google.com/web/fundamentals/primers/service-workers/)

上一篇:Service Workers簡(jiǎn)介(一)

一、緩存并返回請(qǐng)求

現(xiàn)在你已經(jīng)安裝了一個(gè)service worker,你可能想要返回一個(gè)自己緩存的響應(yīng),對(duì)吧些楣?
在你安裝完service worker,用戶導(dǎo)航到另一個(gè)頁(yè)面或者刷新頁(yè)面承绸,service worker 就開(kāi)始接收f(shuō)etch事件兜蠕,例子如下:

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);
      }
    )
  );
});

這里唐片,我們定義了我們的fetch事件莱预,并在event.respondWith()里,我們從caches.match傳入了一個(gè)promise项滑。這個(gè)方法從任何你的service worker緩存的文件中查找結(jié)果依沮。
如果我們有一個(gè)匹配上的response,就返回緩存的值枪狂,否則就返回調(diào)用fetch的結(jié)果危喉,也就是發(fā)起網(wǎng)絡(luò)請(qǐng)求,并返回收到的數(shù)據(jù)州疾。
如果我們想累積緩存一個(gè)新的請(qǐng)求辜限,可以處理fetch請(qǐng)求的response并把這個(gè)response加入緩存,就像下面這樣:

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).then(
          function(response) {
            // Check if we received a valid response
            if(!response || response.status !== 200 || response.type !== 'basic') {
              return response;
            }

            // IMPORTANT: Clone the response. A response is a stream
            // and because we want the browser to consume the response
            // as well as the cache consuming the response, we need
            // to clone it so we have two streams.
            var responseToCache = response.clone();

            caches.open(CACHE_NAME)
              .then(function(cache) {
                cache.put(event.request, responseToCache);
              });

            return response;
          }
        );
      })
    );
});

我們做了這些:

  1. fetch 請(qǐng)求上严蓖,給 .then()增加一個(gè) callback
  2. 一旦我們收到一個(gè)響應(yīng), 我們做這些檢查:
    1. 確認(rèn)響應(yīng)是合法的.
    2. 檢查狀態(tài)是 200.
    3. 確認(rèn)響應(yīng)類型是 basic(說(shuō)明是從我們的源發(fā)起的請(qǐng)求)薄嫡,也就是不緩存第三方文件發(fā)起的請(qǐng)求的響應(yīng).
  3. 如果通過(guò)測(cè)試,我們 克隆 一個(gè)響應(yīng)颗胡。因?yàn)轫憫?yīng)是一個(gè) 毫深,響應(yīng)體只會(huì)被消耗一次。因?yàn)槲覀冃枰o瀏覽器返回響應(yīng)毒姨,并且緩存起來(lái)以便將來(lái)使用, 所以我們需要克隆一下哑蔫,一個(gè)用來(lái)發(fā)給瀏覽器,一個(gè)用來(lái)緩存起來(lái)弧呐。

二闸迷、更新一個(gè)service worker

有時(shí)你的service worker需要更新,此時(shí)你需要:

  1. 更新你的 service worker JavaScript 文件. 當(dāng)用戶來(lái)到你的網(wǎng)頁(yè)俘枫,瀏覽器嘗試重新下載這個(gè)JavaScript 文件腥沽。這個(gè)文件有任何改變,哪怕是一個(gè)字節(jié)崩哩,都會(huì)被認(rèn)為是新的.
  2. 你的新 service worker 將會(huì)啟動(dòng)巡球,install的事件會(huì)被觸發(fā).
  3. 舊的service worker還在控制當(dāng)前頁(yè)面,所以新的service worker會(huì)進(jìn)入一個(gè)等待的狀態(tài)邓嘹。
  4. 當(dāng)前打開(kāi)的頁(yè)面如果被關(guān)閉酣栈,舊的 service worker會(huì)被銷毀,新的開(kāi)始控制汹押。
  5. 一旦新的service worker得到控制權(quán)矿筝,它的activate事件會(huì)被觸發(fā).

我們常常在activate的callback中處理緩存管理。注意:如果你在安裝步驟清掉舊緩存棚贾,那些仍然有控制權(quán)的舊service worker窖维,會(huì)立即停止那個(gè)緩存文件的工作榆综,所以在這里做比較好。

比如說(shuō)铸史,我們有一個(gè)緩存叫 'my-site-cache-v1'鼻疮,我們希望把這個(gè)緩存分割成兩個(gè),一個(gè)給頁(yè)面用琳轿,一個(gè)給博客文章用判沟。那在install(安裝)步驟,我們創(chuàng)建兩個(gè)緩存:'pages-cache-v1' 和 'blog-posts-cache-v1' 崭篡,然后在activate(激活)步驟挪哄,我們刪掉我們的舊緩存'my-site-cache-v1'。

下面的代碼會(huì)循環(huán)查看 service worker 的緩存琉闪,刪掉那些不在白名單上的緩存迹炼。

self.addEventListener('activate', function(event) {

  var cacheWhitelist = ['pages-cache-v1', 'blog-posts-cache-v1'];

  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

三、粗糙的邊緣和陷阱

server worker是個(gè)新玩意兒颠毙。這里提一些問(wèn)題斯入,希望可以盡早被解決,但是現(xiàn)在還是需要注意一下吟秩。

1.安裝失敗的信息無(wú)法告知

如果你注冊(cè)了一個(gè)service worker咱扣,但是沒(méi)在chrome://inspect/#service-workers or chrome://serviceworker-internals中出現(xiàn),那可能是因?yàn)閽伋鲥e(cuò)誤涵防,或者一個(gè)可被傳輸?shù)絜vent.waitUntil()的rejected promise錯(cuò)誤

為了解決這個(gè)問(wèn)題闹伪,前往 chrome://serviceworker-internals 并打開(kāi)谷歌開(kāi)發(fā)工具,對(duì)安裝事件進(jìn)行調(diào)試壮池。 以及配合這篇文章提到的: 《調(diào)試未捕獲的異称浚》

2.fetch的默認(rèn)情況
2.1 沒(méi)有credentials憑據(jù)

當(dāng)你使用fetch時(shí)椰憋,默認(rèn)情況下厅克,請(qǐng)求是不帶credentials憑據(jù)的(比如cookies),如果你需要憑據(jù)橙依,可以這樣使用:

fetch(url, {
  credentials: 'include'
})

對(duì)于同源的URL來(lái)說(shuō)证舟,我們特意這么設(shè)置后, 會(huì)比 XHR復(fù)雜一些。fetch行為和其他的CORS 請(qǐng)求一樣, 比如 <img crossorigin>, 如果你不設(shè)置<img crossorigin="use-credentials">窗骑,它是不會(huì)發(fā)cookies的女责。

2.2 非CORS默認(rèn)安裝失敗

By default, fetching a resource from a third party URL will fail if it doesn't support CORS. You can add a no-CORS option to the Request to overcome this, although this will cause an 'opaque' response, which means you won't be able to tell if the response was successful or not.
默認(rèn)情況下,由于沒(méi)有CORS创译,從第三方URL獲取一個(gè)資源會(huì)失敗抵知。你可以加上一個(gè)no-CORS,盡管這會(huì)導(dǎo)致一些不透明的響應(yīng),因?yàn)槟悴恢理憫?yīng)是否成功刷喜。做法如下:

cache.addAll(urlsToPrefetch.map(function(urlToPrefetch) {
  return new Request(urlToPrefetch, { mode: 'no-cors' });
})).then(function() {
  console.log('All resources have been fetched and cached.');
});

譯者注:如果你不了解no-CORS残制,請(qǐng)查看 request模式-MDN

2.3 處理響應(yīng)式圖像

對(duì)于service worker來(lái)說(shuō),如果你想在安裝步驟緩存一張圖片掖疮,你有幾種選擇:

  • 安裝所有可能用到的圖片
  • 緩存低分辨率版本圖片
  • 緩存高分辨率版本圖片

實(shí)際上你應(yīng)該選擇選項(xiàng)2或3初茶,因?yàn)橄螺d所有圖像會(huì)浪費(fèi)存儲(chǔ)空間。

假設(shè)您在安裝時(shí)選擇低分辨率版本浊闪,并且您希望在加載頁(yè)面時(shí)嘗試從網(wǎng)絡(luò)中檢索更高分辨率的圖像纺蛆,但如果高分辨率圖像失敗,則回退到低分辨率版本规揪。這看起來(lái)很好,但有一個(gè)問(wèn)題温峭。

比如我們有下面兩張圖片:

Screen Density  Width   Height
      1x         400      400
      2x         800      800

我們可能這么使用:

<img src="image-src.png" srcset="image-src.png 1x, image-2x.png 2x" />

如果我們?cè)?x的顯示器上猛铅,瀏覽器會(huì)去下載 image-2x.png,如果離線了凤藏,你可以用.catch() 緩存奸忽,并返回 image-src.png(如果已經(jīng)緩存上的話)。
但是瀏覽器會(huì)期望圖像考慮到2x屏幕上的額外像素揖庄,因此圖像將顯示為200x200 CSS像素而不是400x400 CSS像素栗菜。唯一的方法是在圖像上設(shè)置固定的高度和寬度。

四蹄梢、學(xué)習(xí)更多

這里有一系列關(guān)于 service worker 的文檔: https://jakearchibald.github.io/isserviceworkerready/resources 疙筹,可能對(duì)你有用。

(完)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末禁炒,一起剝皮案震驚了整個(gè)濱河市而咆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌幕袱,老刑警劉巖暴备,帶你破解...
    沈念sama閱讀 222,807評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異们豌,居然都是意外死亡涯捻,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)望迎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)障癌,“玉大人,你說(shuō)我怎么就攤上這事擂煞』烀郑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,589評(píng)論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蝗拿。 經(jīng)常有香客問(wèn)我晾捏,道長(zhǎng),這世上最難降的妖魔是什么哀托? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,188評(píng)論 1 300
  • 正文 為了忘掉前任惦辛,我火速辦了婚禮,結(jié)果婚禮上仓手,老公的妹妹穿的比我還像新娘胖齐。我一直安慰自己,他們只是感情好嗽冒,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布呀伙。 她就那樣靜靜地躺著,像睡著了一般添坊。 火紅的嫁衣襯著肌膚如雪剿另。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,785評(píng)論 1 314
  • 那天贬蛙,我揣著相機(jī)與錄音雨女,去河邊找鬼。 笑死阳准,一個(gè)胖子當(dāng)著我的面吹牛氛堕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播野蝇,決...
    沈念sama閱讀 41,220評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼讼稚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了浪耘?” 一聲冷哼從身側(cè)響起乱灵,我...
    開(kāi)封第一講書(shū)人閱讀 40,167評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎七冲,沒(méi)想到半個(gè)月后痛倚,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,698評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡澜躺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評(píng)論 3 343
  • 正文 我和宋清朗相戀三年蝉稳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掘鄙。...
    茶點(diǎn)故事閱讀 40,912評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡耘戚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出操漠,到底是詐尸還是另有隱情收津,我是刑警寧澤饿这,帶...
    沈念sama閱讀 36,572評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站撞秋,受9級(jí)特大地震影響长捧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吻贿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評(píng)論 3 336
  • 文/蒙蒙 一串结、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧舅列,春花似錦肌割、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,746評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至榨惠,卻和暖如春先巴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背冒冬。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,859評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留摩渺,地道東北人简烤。 一個(gè)月前我還...
    沈念sama閱讀 49,359評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像摇幻,于是被迫代替她去往敵國(guó)和親横侦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容