Hizmet çalışanı önbelleğe alma stratejileri

Şimdiye kadar Cache arayüzünde yalnızca bahsediliyor ve küçük kod snippet'leri gösteriliyordu. Service Worker'ları verimli bir şekilde kullanmak için bir veya daha fazla önbelleğe alma stratejisi benimsemeniz gerekir. Bunun için Cache arayüzüne aşina olmanız gerekir.

Önbelleğe alma stratejisi, hizmet çalışanının fetch etkinliği ile Cache arayüzü arasındaki etkileşimdir. Önbelleğe alma stratejisinin nasıl yazıldığı değişiklik gösterir. Örneğin, statik öğe isteklerinin dokümanlardan farklı şekilde işlenmesi tercih edilebilir ve bu, önbelleğe alma stratejisinin nasıl oluşturulacağını etkiler.

Stratejilere geçmeden önce, Cache arayüzünün ne olmadığı ve ne olduğu hakkında konuşalım ve Service Worker önbelleklerini yönetmek için sunduğu yöntemlerden bazılarını kısaca özetleyelim.

Cache arayüzü ile HTTP önbelleği karşılaştırması

Daha önce Cache arayüzüyle hiç çalışmadıysanız bu arayüzün HTTP önbelleğiyle aynı veya en azından HTTP önbelleğiyle ilişkili olduğunu düşünmek cazip gelebilir. Bu doğru değildir.

  • Cache arayüzü, HTTP önbelleğinden tamamen ayrı bir önbelleğe alma mekanizmasıdır.
  • HTTP önbelleğini etkilemek için kullandığınız Cache-Control yapılandırması, Cache arayüzünde hangi öğelerin depolanacağı konusunda herhangi bir etkiye sahip değildir.

Tarayıcı önbelleklerini katmanlı olarak düşünebiliriz. HTTP önbelleği, HTTP üst bilgilerinde ifade edilen yönergelere sahip anahtar/değer çiftleri tarafından çalıştırılan alt düzey bir önbellektir.

Cache arayüzü ise buna karşılık bir JavaScript API tarafından çalıştırılan üst düzey bir önbellektir. Bu, nispeten basit HTTP anahtar/değer çiftlerini kullanmaya kıyasla daha fazla esneklik sunar ve önbelleğe alma stratejilerini mümkün kılanın yarısıdır. Hizmet çalışanı önbellekleriyle ilgili bazı önemli API yöntemleri şunlardır:

  • Yeni bir Cache örneği oluşturmak için CacheStorage.open.
  • Cache.add ve Cache.put kullanarak ağ yanıtlarını bir Service Worker önbelleğinde depolayın.
  • Cache örneğinde önbelleğe alınan yanıtı bulmak için Cache.match.
  • Cache örneğinden önbelleğe alınan bir yanıtı kaldırmak için Cache.delete.

Müşterilerimizden birkaçı aşağıda yer alıyor. Başka faydalı yöntemler de vardır, ancak bu kılavuzun ilerleyen bölümlerinde göreceğiniz temel yöntemler bunlardır.

Mütevazı fetch etkinliği

Önbelleğe alma stratejisinin diğer yarısı, hizmet çalışanının fetch etkinliğidir. Bu dokümanda şu ana kadar "ağ isteklerine müdahale etme" hakkında biraz bilgi edindiniz. Service Worker içindeki fetch etkinliğinde bu işlemlerin gerçekleştiği yer alır:

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

Bu, oyuncak bir örneğidir ve iş sırasında bunu görebilirsiniz. Ancak, hizmet çalışanlarının neler yapabileceğine göz atmanıza olanak tanıyan bir örnektir. Yukarıdaki kod, aşağıdakileri yapar:

  1. Bunun bir resim isteği olup olmadığını öğrenmek için isteğin destination özelliğini inceleyin.
  2. Resim, hizmet çalışanı önbelleğindeyse buradan yayınlayın. Aksi takdirde resmi ağdan getirin, yanıtı önbellekte depolayın ve ağ yanıtını döndürün.
  3. Diğer tüm istekler, önbellekle etkileşime gerek kalmadan hizmet çalışanı üzerinden iletilir.

Bir getirmenin event nesnesi, her isteğin türünü tanımlamanıza yardımcı olacak bazı yararlı bilgi parçalarını içeren bir request özelliği içerir:

  • url. Bu, şu anda fetch etkinliği tarafından işlenen ağ isteğinin URL'sidir.
  • method, istek yöntemidir (ör. GET veya POST).
  • İsteğin modunu açıklayan mode. 'navigate' değeri genellikle HTML dokümanı isteklerini diğer isteklerden ayırt etmek için kullanılır.
  • destination: İstenen içeriğin türünü, istenen öğenin dosya uzantısının kullanılmasını önleyecek şekilde açıklar.

Aynı şekilde, eşzamansız oyunun adı da bu. install etkinliğinin, taahhüt veren bir event.waitUntil yöntemi sunduğunu ve etkinleştirme işlemine devam etmeden önce bunun çözümlenmesini beklediğini hatırlarsınız. fetch etkinliği, eşzamansız bir fetch isteği veya Cache arayüzünün match yöntemi tarafından döndürülen bir yanıtın sonucunu döndürmek için kullanabileceğiniz benzer bir event.respondWith yöntemi sunar.

Önbelleğe alma stratejileri

Cache örnekleri ve fetch etkinlik işleyicisi hakkında biraz bilgi sahibi olduğunuza göre bazı Service Worker önbelleğe alma stratejilerini ayrıntılı olarak incelemeye hazırsınız. Olasılıklar neredeyse sonsuz olsa da bu kılavuz Workbox'la birlikte sunulan stratejilere bağlı kalacak, böylece Workbox'ın dahili bileşenlerinde neler olup bittiğini anlayabilirsiniz.

Yalnızca önbellek

Sayfadan hizmet çalışanına ve önbelleğe arasındaki akışı gösterir.

"Yalnızca Önbellek" adını verdiğimiz basit bir önbelleğe alma stratejisiyle başlayalım. Nedeni, hizmet çalışanı sayfanın kontrolünde olduğunda eşleşen istekler sadece önbelleğe gider. Bu, kalıbın çalışması için önbelleğe alınan tüm öğelerin önceden önbelleğe alınması gerektiği ve bu öğelerin, hizmet çalışanı güncellenene kadar önbellekte hiçbir zaman güncellenmemesi gerektiği anlamına gelir.

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

Yukarıda, bir öğe dizisi yükleme sırasında önbelleğe alınır. Service Worker getirmeleri işlediğinde, fetch etkinliği tarafından işlenen istek URL'sinin önceden önbelleğe alınmış öğeler dizisinde olup olmadığını kontrol ederiz. Böyle bir durumda kaynağı önbellekten alır ve ağı atlarız. Diğer istekler ağa ve yalnızca ağa geçer. Bu stratejinin nasıl uygulandığını görmek için konsolunuz açıkken bu demoya göz atın.

Yalnızca ağ

Sayfadan hizmet çalışanına veya ağa giden akışı gösterir.

"Yalnızca Önbellek"in tersi "Yalnızca Ağ"dır. Burada istek, bir hizmet çalışanı aracılığıyla, hizmet çalışanı önbelleğiyle herhangi bir etkileşim olmadan ağa iletilir. Bu, içeriğin güncel olmasını sağlamak (işaretlemeyi düşünün) için iyi bir stratejidir. Ancak bunun karşılığında, bu strateji kullanıcı çevrimdışı olduğunda asla çalışmayacaktır.

Bir isteğin ağa iletildiğinden emin olmak, eşleşen bir istek için event.respondWith numaralı telefonu aramamanız anlamına gelir. Ağa iletmek istediğiniz isteklerin açıkça belirtilmesini istiyorsanız fetch etkinliği geri çağırma işlevinizde boş bir return; değerini ekleyebilirsiniz. Önbelleğe alınmamış istekler için "Yalnızca Önbellek" strateji demosunda bu işlem yapılır.

Önce önbelleğe alın, ağa geri döner

Sayfadan hizmet çalışanına, önbelleğe, önbellekte yoksa ağa giden akışı gösterir.

Bu stratejide işler biraz daha karışır. Eşleşen istekler için süreç şu şekilde işler:

  1. İstek önbelleğe alınır. Öğe önbellekteyse buradan yayınlayın.
  2. İstek önbellekte değilse ağa gidin.
  3. Ağ isteği tamamlandıktan sonra bunu önbelleğe ekleyin, ardından ağdan yanıtı döndürün.

Bu stratejinin örneğini canlı bir demoda test edebilirsiniz:

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

Bu örnekte yalnızca resimler ele alınsa da bu, özellikle karma sürümler başta olmak üzere tüm statik öğelere (CSS, JavaScript, resimler ve yazı tipleri gibi) uygulamak için mükemmel bir stratejidir. HTTP önbelleğinin başlatabileceği içerik güncelliği kontrollerini sunucuyla sekteye uğratarak sabit öğelerin hızını artırır. Daha da önemlisi, önbelleğe alınan tüm öğeler çevrimdışı kullanılabilir olur.

Önce ağ, önbelleğe alma

Sayfadan hizmet çalışanına, ağa ve ağ yoksa önbelleğe kadar olan akışı gösterir.

"Önce ağ, sonra ağ, ikincisi" ayarını yaparsanız sonuçta "Önce ağ, sonra önbellek" stratejisi kalırsınız:

  1. Bir istek için önce ağa gider ve yanıtı önbelleğe yerleştirirsiniz.
  2. Daha sonra çevrimdışı olursanız önbellekte o yanıtın en son sürümüne geri dönersiniz.

Bu strateji, çevrimiçi durumdayken bir kaynağın en son sürümüne sahip olmak ve kullanılabilir en son sürüme çevrimdışı erişim vermek istediğinizde HTML veya API istekleri için idealdir. HTML isteklerine uygulandığında bu durum aşağıdaki gibi görünebilir:

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

self.addEventListener('fetch', (event) => {
  // Check if this is a navigation request
  if (event.request.mode === 'navigate') {
    // Open the cache
    event.respondWith(caches.open(cacheName).then((cache) => {
      // Go to the network first
      return fetch(event.request.url).then((fetchedResponse) => {
        cache.put(event.request, fetchedResponse.clone());

        return fetchedResponse;
      }).catch(() => {
        // If the network is unavailable, get
        return cache.match(event.request.url);
      });
    }));
  } else {
    return;
  }
});

Bunu bir demoda deneyebilirsiniz. Önce sayfaya gidin. HTML yanıtının önbelleğe alınmadan önce yeniden yüklenmesi gerekebilir. Ardından geliştirici araçlarınızda çevrimdışı bağlantı simüle edin ve sayfayı yeniden yükleyin. Kullanılabilir son sürüm, önbellekten anında sunulur.

Çevrimdışı kapasitenin önemli olduğu, ancak bu kapasite ile bir işaretleme veya API verisinin en son sürümüne erişim arasında denge kurmanız gerektiği durumlarda, "Önce ağ, sonra önbellek", bu hedefe ulaşmanızı sağlayan sağlam bir stratejidir.

Eski-ancak-tekrar doğrula

Sayfadan hizmet çalışanına, önbelleğe, ardından ağdan önbelleğe akışı gösterir.

Şimdiye kadar ele aldığımız stratejiler arasında "Eski değeri yeniden doğrula" seçeneği en karmaşık olanıdır. Bu, bazı yönlerden son iki stratejiye benzer, ancak prosedür hem bir kaynak için erişim hızına öncelik verir hem de arka planda güncel kalır. Bu stratejinin işleyiş şekli şöyledir:

  1. Bir öğe için yapılan ilk istekte öğeyi ağdan getirin, önbelleğe yerleştirin ve ağ yanıtını döndürün.
  2. Sonraki isteklerde, öğeyi önce önbellekten sunun, ardından "arka planda" ağdan yeniden isteyin ve öğenin önbellek girişini güncelleyin.
  3. Bundan sonraki istekler için önceki adımda önbelleğe yerleştirilmiş ağdan getirilen son sürümü alırsınız.

Bu, güncel kalmak için önemli olan biraz önem taşıyan, ancak hayati önem taşımayan konular için mükemmel bir stratejidir. Öğeleri, bir sosyal medya sitesinin avatarları gibi düşünün. Kullanıcılar bunu yapmaya başladıklarında güncellerler, ancak her istekte en son sürüm şart değildir.

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

self.addEventListener('fetch', (event) => {
  if (event.request.destination === 'image') {
    event.respondWith(caches.open(cacheName).then((cache) => {
      return cache.match(event.request).then((cachedResponse) => {
        const fetchedResponse = fetch(event.request).then((networkResponse) => {
          cache.put(event.request, networkResponse.clone());

          return networkResponse;
        });

        return cachedResponse || fetchedResponse;
      });
    }));
  } else {
    return;
  }
});

Özellikle tarayıcınızın geliştirici araçlarındaki ağ sekmesine ve CacheStorage görüntüleyicisine (tarayıcınızın geliştirici araçlarında böyle bir araç varsa) dikkat ederseniz bu işlemin başka bir canlı demoda görebilirsiniz.

Çalışma Kutusu'na geçiyoruz.

Bu belge, Service Worker'ın API'si ve ilgili API'lerle ilgili incelememizi özetlemiştir.