Skip to content
This repository has been archived by the owner on Jun 13, 2023. It is now read-only.

Service Worker Caching Strategy

HYUNJIN LEE edited this page Aug 10, 2022 · 9 revisions

개요

서비스 워커를 효과적으로 사용하려면 캐싱 전략을 잘 선택하는 것이 중요하다. 캐싱 전략을 세우려면 Cache 인터페이스에 대한 이해가 필요하다.

캐싱 전략은 서비스 워커의 fetch 이벤트와 Cache 인터페이스 간의 상호 작용이다. 예를 들어 정적 요소에 대한 요청을 문서와 다르게 처리하는 것이 바람직할 수 있으며 이는 캐싱 전략이 구성되는 방식에 영향을 미친다.

Cache interface vs HTTP Cache

Cache 인터페이스와 HTTP Cache는 관련이 없다.

  • The Cache interface is a caching mechanism entirely separate from the HTTP cache.
  • Whatever Cache-Control configuration you use to influence the HTTP cache has no influence on what assets get stored in the Cache interface.

HTTP 캐시에 영향을 주기 위해 사용되는 Cache-Control 구성은 Cache 인터페이스에 영향을 미치지 못하므로, 브라우저 캐시를 계층화된 것으로 생각할 수 있다.

HTTP 캐시는 HTTP 헤더에 표현된 지시문과 함께 키-값 쌍에 의해 구동되는 저수준 캐시이다. 이와 대조적으로 Cache 인터페이스 JavaScript API에 의해 구동되는 고급 캐시이다.

Cache 인터페이스는 상대적으로 단순한 HTTP 키-값 쌍을 사용할 때보다 더 많은 유연성을 제공하며 캐싱 전략을 가능하게합니다. 서비스 워커 캐시와 관련된 몇가지 중요한 API는 다음과 같습니다.

  • CacheStorage.open
  • Cache.add & Cache.put
  • Cache.match (to locate a cached response in a Cache instance)
  • Cache.delete (to remove a cached response from a Cache instance)

fetch event

아래는 fetch event와 Cache 인터페이스의 예제 코드이다.

// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';

self.addEventListener('install', (event) => {
  event.waitUntil(caches.open(cacheName));
});

self.addEventListener('fetch', async (event) => {
  // Is this a request for an image?
  if (event.request.destination === 'image') {
    // Open the cache
    event.respondWith(caches.open(cacheName).then((cache) => {
      // Respond with the image from the cache or from the network
      return cache.match(event.request).then((cachedResponse) => {
        return cachedResponse || fetch(event.request.url).then((fetchedResponse) => {
          // Add the network response to the cache for future visits.
          // Note: we need to make a copy of the response to save it in
          // the cache and use the original as the request response.
          cache.put(event.request, fetchedResponse.clone());

          // Return the network response
          return fetchedResponse;
        });
      });
    }));
  } else {
    return;
  }
});
  1. Inspect the request's destination property to see if this is an image request.
  2. If the image is in the service worker cache, serve it from there. If not, fetch the image from the network, store the response in the cache, and return the network response.
  3. All other requests are passed through the service worker with no interaction with the cache.

fetch 이벤트 객체는 각 요청의 유형을 식별하는데 도움이 되는 몇가지 유용한 정보가 있는 요청 속성이 포함되어 있다.

  • url: which is the URL for the network request currently being handled by the fetch event.
  • method: which is the request method (e.g, GET or POST)
  • mode: which describes the request's mode. A value of 'navigate' is often used to distinguish requests for HTML documents from other requests.
  • destination: which describes the type of content being requested in a way that avoids using the requested asset's file extension.

Caching Strategies

Cache Only

image

Cache Only는 서비스 워커가 페이지를 제어할 때 일치하는 요청은 캐시로만 이동합니다. 즉, 이 패턴이 작동하려면 asset을 미리 캐시해야되며 서비스 워커가 업데이트될 때까지 해당 자산이 캐시에서 업데이트되지 않습니다.

// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';

// Assets to precache
const precachedAssets = [
  '/possum1.jpg',
  '/possum2.jpg',
  '/possum3.jpg',
  '/possum4.jpg'
];

self.addEventListener('install', (event) => {
  // Precache assets on install
  event.waitUntil(caches.open(cacheName).then((cache) => {
    return cache.addAll(precachedAssets);
  }));
});

self.addEventListener('fetch', (event) => {
  // Is this one of our precached assets?
  const url = new URL(event.request.url);
  const isPrecachedRequest = precachedAssets.includes(url.pathname);

  if (isPrecachedRequest) {
    // Grab the precached asset from the cache
    event.respondWith(caches.open(cacheName).then((cache) => {
      return cache.match(event.request.url);
    }));
  } else {
    // Go to the network
    return;
  }
});

위 코드에서 asset들은 install 타임에 미리 캐시된다.

서비스워커가 fetch 이벤트를 처리할 때 요청 URL이 precached assets에 있는지 확인하고 있다면 cache를 리턴한다. 다른 리소스는 network로 요청을 보낼 것이다.

Cache first, falling back to network

image

  1. The request hits the cache. If the asset is in the cache, serve it from there.
  2. If the request is not in the cache, go to the network.
  3. Once the network request finishes, add it to the cache, then return the response from the network.
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';

self.addEventListener('fetch', (event) => {
  // Check if this is a request for an image
  if (event.request.destination === 'image') {
    event.respondWith(caches.open(cacheName).then((cache) => {
      // Go to the cache first
      return cache.match(event.request.url).then((cachedResponse) => {
        // Return a cached response if we have one
        if (cachedResponse) {
          return cachedResponse;
        }

        // Otherwise, hit the network
        return fetch(event.request).then((fetchedResponse) => {
          // Add the network response to the cache for later visits
          cache.put(event.request, fetchedResponse.clone());

          // Return the network response
          return fetchedResponse;
        });
      });
    }));
  } else {
    return;
  }
});

Network first, falling back to cache

Stale While Revalidate

stale-while-revalidate는 개발자가 캐시된 콘텐츠를 즉시 로드하는 즉시성과 캐시된 컨텐츠에 대한 업데이트가 향후에 사용되도록 보장하는 최신성 간의 균형을 유지하는데 도움이된다. 정기적으로 업데이트되는 서드파티 웹 서비스 또는 라이브러리를 유지 관리하거나 asset 수명이 잛은 경향이 있는 경우 stale-while-revalidate가 기존 캐싱 정책에 유용한 추가 기능이 될 수 있다.