iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 12
1

Cache then Network Strategies

這個策略算是目前應用場景最為廣泛的。主要目的就是能「從cache中盡快的獲得用戶所需要的資源」,並且「同時也透過網路去fetch該資源」,若fetch回來的資源為較新的版本,則取代從cache中獲得的資源來傳給用戶。(可以把它想成是Network with Cache Fallback Strategies的進階版。因為當網路不穩定時,用戶不在需要等待過長的時間)

  1. 一開始我們直接用Javascript去存取cache中的資源,同時也透過service worker來攔截發出的fetch request。
  2. 若cache中有該資源,則直接會傳給用戶。另外service worker也在有網路連線的情形下去向外部獲取資源。
  3. service worker成功地從網路獲取該資源。
  4. 接著透過dynamic caching將該資源暫存到cache中,以便下次訪問該資源,能更快速地回覆給用戶。
  5. 最後service worker將fetch回來的response回傳到頁面。

來看一下在我的PWA project要怎麼實現這個策略吧:(首先這邊不是在service woker中撰寫,而是要在feed.js中來存取cache)

var url = 'https://httpbin.org/get';  // 我們就是要從該外部server的API獲取資源
var networkDataReceived = false;

fetch(url).then(function(res) {
    return res.json();
  }).then(function(data) {
    networkDataReceived = true;
    console.log('From Web', data);
    clearCards();
    createCard();
  });

if('caches' in window) {
  caches.match(url).then(function(response) {
    if(response) {
      return response.json();
    }
  }).then(function(data) {
    console.log('From Cache', data);
    if(!networkDataReceived) {
      clearCards();
      createCard();
    }
  });
}
function clearCards() {
  while(sharedMomentsArea.hasChildNodes()) {
    sharedMomentsArea.removeChild(sharedMomentsArea.lastChild);
  }
}

這邊說明一下我的程式邏輯,一開始先用fetch API來獲取外部server的資源,並同時確認caches是否在window object中,如果瀏覽器有支援就到cache中尋找是否有相對應已經暫存的資源,有的話就回傳。

這邊為了避免我同時成功地從「cache」和「網路上」獲取該資源,重複執行了createCards(),我使用networkDataReceived這個布林變數來去做判斷。當fetch API先回傳我們要的資源,我們只需要針對這個回傳的資料來建立我們的card(貼文)。就算cache裡存在我們要的資源也不必再建立一個card。

再來就是我新增了一個clearCards() function,並加在createCards()前。這樣每次載入我的PWA時,都會全部重新刪掉這些cards,避免累加重複的cards越來越多,之後再將fetch回來的資源重新建立cards。


眼尖的人可能會發現,前面流程圖的第4和5步驟還沒有寫RR(也就是在service worker中針對fetch回來的資源使用dynamic caching)。那我們接著就來看一下要怎麼在sw.js file中加入這段邏輯吧!! /images/emoticon/emoticon28.gif

// Cache then network
self.addEventListener('fetch', function(event) {
    event.respondWith(
        caches.open(CACHE_DYNAMIC_NAME).then(function(cache) {
            return fetch(event.request).then(function(res) {
                cache.put(event.request, res.clone());
                return res;
            });
        })
    );
});

一樣地在service worker監聽fetch event時,將透過網路fetch回來的response,使用cache.put()添加到dynamic cache中,並回傳該response。

不過,當offline時畫面結果卻是....Why??

仔細看一下我剛在service worker中寫的那段code,其實我並沒有寫service worker要到cache中獲取資源的程式碼QQ,我只是put進去後就回傳了。

也就是說我們所有的fetch request被service worker攔截後,如果今天在沒有網路連線的情形下,它去fetch所有不管是「App shell中的靜態資源」還是「動態資源」都會失敗。

不過這也正是cache than network的使用場景,它會在網路正常連線時,快速的從cache中獲取該資源給用戶。但這個策略流程並不能在沒有網路連線時,從cache中獲取資源。

為了在離線時也能正常運作,這邊要再修改剛剛寫的code。我要將「cache then network strategies」和之前所寫的「cache with network fallback strategies」根據不同的request來使用不同的策略:

// Cache then Network
self.addEventListener('fetch', function(event) {
    var url = 'https://httpbin.org/get';

    if(event.request.url.indexOf(url) > -1) {
        event.respondWith(
            caches.open(CACHE_DYNAMIC_NAME).then(function(cache) {
                return fetch(event.request).then(function(res) {
                    cache.put(event.request, res.clone());
                    return res;
                });
            })
        );
    } else {
        event.respondWith(
            caches.match(event.request).then(function(response) {
                if(response) {
                    return response;
                } else {
                    return fetch(event.request).then(function(res) {
                        return caches.open(CACHE_DYNAMIC_NAME).then(function(cache) {
                            cache.put(event.request.url, res.clone());
                            return res;
                        })
                    }).catch(function(err) {
                        return caches.open(CACHE_STATIC_NAME).then(function(cache) {
                            return cache.match('/offline.html');
                        });
                    });
                }
            })
        );
    }
});

這邊我將「要去fetch外部server資料的request」才使用「cache then network strategies」,而其他的request則是使用我們之前所寫的「cache with network fallback strategies」。這樣的話當offline時,在cache中的App shell靜態資源或是其他動態資源就都可以回傳了。

Day12 結束!! /images/emoticon/emoticon37.gif


上一篇
[Day11] Service Worker進階Caching實作(Part1)
下一篇
[Day13] Service Worker進階Caching實作(Part3)
系列文
你應該要知道的新一代Web技術---漸進式網頁(PWA)29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言