Çevrimdışı Yemek Kitabı

Jake Archibald
Jake Archibald

Service Worker sayesinde ise çevrimdışı çözüm denemekten vazgeçtik ve geliştiricilere, sorunu kendi başlarına çözmeleri için hareketli parçalar verdik. Önbelleğe alma ve isteklerin işlenme şekli üzerinde kontrol sahibi olmanızı sağlar. Bu, kendi kalıplarınızı oluşturmanız gerektiği anlamına gelir. İzole haldeki birkaç olası kalıba göz atalım. Ancak uygulamada muhtemelen URL ve bağlama göre bunların birçoğunu yan yana kullanırsınız.

Bu kalıplardan bazılarının çalışan bir demosu için Heyecan uyandırmak için eğitildi bölümüne ve performansa etkisini gösteren bu videoya göz atın.

Önbellek makinesi: kaynakların ne zaman depolanacağı

Service Worker, istekleri önbelleğe alma işleminden bağımsız olarak ele almanıza olanak tanır. Bu nedenle istekleri ayrı ayrı göstereceğim. İlk olarak, önbelleğe alma ne zaman yapılmalı?

Yüklemede (bağımlılık olarak)

Yüklemede - bağımlılık olarak.
Yükleme sırasında - bağımlılık olarak.

Hizmet Çalışanı size bir install etkinliği verir. Bunu, diğer etkinliklere başlamadan önce hazırlanması gereken öğeleri hazırlamak için kullanabilirsiniz. Bu durum, Hizmet Çalışanınızın önceki herhangi bir sürümü çalışmaya ve sayfaları sunmaya devam eder. Bu nedenle, burada yaptığınız işlemler bunu kesintiye uğratmamalıdır.

Şunlar için idealdir: CSS, resimler, yazı tipleri, JS, şablonlar... sitenizin bu "sürümü" için statik olduğunu düşündüğünüz her şey.

Bunlar, getirilmemesi durumunda sitenizi tamamen çalışmaz hale getirir, buna karşılık platforma özgü eşdeğer bir uygulama da ilk indirme işlemine dahil edilir.

self.addEventListener('install', function (event) {
  event.waitUntil(
    caches.open('mysite-static-v3').then(function (cache) {
      return cache.addAll([
        '/css/whatever-v3.css',
        '/css/imgs/sprites-v6.png',
        '/css/fonts/whatever-v8.woff',
        '/js/all-min-v4.js',
        // etc.
      ]);
    }),
  );
});

event.waitUntil, yüklemenin uzunluğunu ve başarısını tanımlama sözü verir. Vaat reddedilirse yükleme bir hata olarak kabul edilir ve bu Hizmet Çalışanı terk edilir (daha eski bir sürüm çalışıyorsa bu işlem olduğu gibi bırakılır). caches.open() ve cache.addAll() tarafından iade sözü verildi. Kaynaklardan herhangi biri getirilemezse cache.addAll() çağrısı reddedilir.

Eğitilen deneyimde bunu statik öğeleri önbelleğe almak için kullanıyorum.

Bağımlılık olarak değil, yükleme sırasında

Yükleme sırasında - bağımlılık olarak değil.
Yükleme sırasında - bağımlılık olarak değil.

Bu işlem yukarıdakine benzerdir ancak yüklemenin tamamlanmasını geciktirmez ve önbelleğe alma başarısız olursa yüklemenin başarısız olmasına neden olmaz.

Şunlar için idealdir:Bir oyunun sonraki seviyelerinde kullanıma sunulan öğeler gibi hemen ihtiyaç duyulmayan daha büyük kaynaklar.

self.addEventListener('install', function (event) {
  event.waitUntil(
    caches.open('mygame-core-v1').then(function (cache) {
      cache
        .addAll
        // levels 11–20
        ();
      return cache
        .addAll
        // core assets and levels 1–10
        ();
    }),
  );
});

Yukarıdaki örnek, 11-20. seviyeler için cache.addAll sözünü event.waitUntil için yerine getirmez. Bu nedenle, başarısız olsa bile oyun çevrimdışı kullanılabilir olmaya devam eder. Elbette, bu düzeylerin olası eksikliklerini karşılamalı ve eksiklerse bunları önbelleğe almayı yeniden deneyebilirsiniz.

Etkinliklerin işlenmesi tamamlandığı için Hizmet Çalışanı, 11-20. seviyelerde indirme sırasında sonlandırılabilir. Diğer bir deyişle, önbelleğe alınmaz. Gelecekte Web Periodic Arka Plan Senkronizasyonu API'si bu tür durumları ve filmler gibi daha büyük indirme işlemlerini halledecektir. Bu API şu anda yalnızca Chromium çatallarında desteklenmektedir.

Etkin olduğunda

Etkin olduğunda.
Etkinleştirildiğinde.

Temizleme ve taşıma için idealdir.

Yeni bir Service Worker yüklendikten ve önceki sürüm kullanılmadığında, yenisi etkinleştirilir ve bir activate etkinliği alırsınız. Eski sürüm kullanımdan kaldırıldığından IndexedDB'deki şema taşıma işlemlerini gerçekleştirmek ve kullanılmayan önbellekleri silmek için iyi bir zamandır.

self.addEventListener('activate', function (event) {
  event.waitUntil(
    caches.keys().then(function (cacheNames) {
      return Promise.all(
        cacheNames
          .filter(function (cacheName) {
            // Return true if you want to remove this cache,
            // but remember that caches are shared across
            // the whole origin
          })
          .map(function (cacheName) {
            return caches.delete(cacheName);
          }),
      );
    }),
  );
});

Etkinleştirme sırasında fetch gibi diğer etkinlikler sıraya alınır. Bu nedenle, uzun bir etkinleştirme işlemi sayfa yüklemeyi engelleyebilir. Etkinleştirmenizi mümkün olduğunca az tutun ve yalnızca eski sürüm etkinken yapamayacağınız şeyler için kullanın.

Eğitilen deneyimde bunu eski önbellekleri kaldırmak için kullanıyorum.

Kullanıcı etkileşiminde

Kullanıcı etkileşiminde.
Kullanıcı etkileşiminde.

Şunlar için idealdir:Sitenin tamamı çevrimdışına alınamadığında ve kullanıcının çevrimdışıyken kullanmak istediği içeriği seçmesine izin vermeyi seçtiğiniz durumlarda. Örneğin, YouTube gibi bir video, Wikipedia'daki bir makale, Flickr'daki belirli bir galeri.

Kullanıcıya "Daha sonra oku" veya "Çevrimdışı kullanım için kaydet" düğmesi ekleyin. Tıklandığında ağdan ihtiyacınız olan şeyi alın ve önbellekte açın.

document.querySelector('.cache-article').addEventListener('click', function (event) {
  event.preventDefault();

  var id = this.dataset.articleId;
  caches.open('mysite-article-' + id).then(function (cache) {
    fetch('/get-article-urls?id=' + id)
      .then(function (response) {
        // /get-article-urls returns a JSON-encoded array of
        // resource URLs that a given article depends on
        return response.json();
      })
      .then(function (urls) {
        cache.addAll(urls);
      });
  });
});

caches API hem sayfalardan hem de Service Worker'lardan kullanılabilir. Yani doğrudan sayfa üzerinden önbelleğe ekleme yapabilirsiniz.

Ağ yanıtında

Ağ yanıtında.
Ağ yanıtında.

Şunlar için idealdir:Kullanıcının gelen kutusu veya makale içeriği gibi kaynakları sık sık güncelleme. Avatar gibi önemsiz içerikler için de kullanışlıdır ancak dikkatli olmanız gerekir.

Bir istek, önbellekteki hiçbir şeyle eşleşmiyorsa isteği ağdan alın, sayfaya gönderin ve aynı anda önbelleğe ekleyin.

Bunu avatarlar gibi bir dizi URL için yapıyorsanız kaynağınızın depolama alanını şişirmemeye dikkat etmeniz gerekir. Kullanıcının disk alanını geri alması gerekiyorsa birincil aday olmak istemezsiniz. Önbellekte artık ihtiyacınız olmayan öğeleri kaldırdığınızdan emin olun.

self.addEventListener('fetch', function (event) {
  event.respondWith(
    caches.open('mysite-dynamic').then(function (cache) {
      return cache.match(event.request).then(function (response) {
        return (
          response ||
          fetch(event.request).then(function (response) {
            cache.put(event.request, response.clone());
            return response;
          })
        );
      });
    }),
  );
});

Verimli bellek kullanımı sağlamak için bir yanıtın/isteğin gövdesini yalnızca bir kez okuyabilirsiniz. Yukarıdaki kod, ayrı olarak okunabilecek ek kopyalar oluşturmak için .clone() kullanır.

Eğlenmek için eğitildiğinde bunu Flickr görsellerini önbelleğe almak için kullanıyorum.

Eski-yeniden doğrula

Eski-yeniden doğrula'yı seçin.
Yeniden doğrulama sırasında geçersiz kılın.

Şunlar için idealdir:En son sürüme sahip olmanın gerekli olmadığı durumlarda kaynakları sık sık güncellemek. Avatarlar bu kategoriye girebilir.

Önbelleğe alınmış bir sürüm varsa onu kullanın, ancak bir dahaki sefere güncelleme getirin.

self.addEventListener('fetch', function (event) {
  event.respondWith(
    caches.open('mysite-dynamic').then(function (cache) {
      return cache.match(event.request).then(function (response) {
        var fetchPromise = fetch(event.request).then(function (networkResponse) {
          cache.put(event.request, networkResponse.clone());
          return networkResponse;
        });
        return response || fetchPromise;
      });
    }),
  );
});

Bu, HTTP'nin stale-when-revalidate işlevine çok benzer.

Push mesajında

Push mesajında.
Push mesajında.

Push API, Service Worker üzerine inşa edilen başka bir özelliktir. Bu işlem, OS'in mesajlaşma hizmetinden gelen bir iletiye yanıt olarak Service Worker'ın uyandırılmasına olanak tanır. Bu durum, kullanıcı sitenizde açık bir sekme olmadığında bile gerçekleşir. Yalnızca Service Worker uyanılır. Bunu yapmak için bir sayfadan izin istediğinizde kullanıcıdan istenir.

Şunlar için uygundur: sohbet mesajı, son dakika haberi veya e-posta gibi bildirimle ilgili içerik. Ayrıca, yapılacaklar listesi güncellemesi veya takvim değişikliği gibi anında senkronizasyondan faydalanan, nadir değişen içerikler de

Yaygın nihai sonuç, dokunulduğunda ilgili sayfayı açan/ilgili sayfayı açan/odaklanan ancak bu işlemden önce önbellekleri güncellemenin extremely önemli olduğu bir bildirimdir. Kullanıcının push mesajı aldığı sırada internete bağlı olduğu anlamına gelir, ancak kullanıcı sonunda bildirimle etkileşim kurduğu zamanda olmayabilir. Dolayısıyla bu içeriğin çevrimdışı olarak kullanılabilir olması önemlidir.

Bu kod, bildirim göstermeden önce önbelleği günceller:

self.addEventListener('push', function (event) {
  if (event.data.text() == 'new-email') {
    event.waitUntil(
      caches
        .open('mysite-dynamic')
        .then(function (cache) {
          return fetch('/inbox.json').then(function (response) {
            cache.put('/inbox.json', response.clone());
            return response.json();
          });
        })
        .then(function (emails) {
          registration.showNotification('New email', {
            body: 'From ' + emails[0].from.name,
            tag: 'new-email',
          });
        }),
    );
  }
});

self.addEventListener('notificationclick', function (event) {
  if (event.notification.tag == 'new-email') {
    // Assume that all of the resources needed to render
    // /inbox/ have previously been cached, e.g. as part
    // of the install handler.
    new WindowClient('/inbox/');
  }
});

Arka planda senkronizasyonda

Arka planda senkronizasyonda.
Arka plan senkronizasyonunda.

Arka plan senkronizasyonu, Service Worker'ın üzerine inşa edilen başka bir özelliktir. Arka plan veri senkronizasyonunu tek seferlik veya (son derece sezgisel) bir aralıkta istemenize olanak tanır. Bu durum, kullanıcı sitenizde açık bir sekme olmadığında bile gerçekleşir. Yalnızca Hizmet Çalışanı uyanır. Bunu yapmak için bir sayfadan izin istediğinizde kullanıcıdan istenir.

Şu durumlar için idealdir: Acil olmayan güncellemeler, özellikle de kullanıcılar için güncelleme başına bir push mesajının çok sık meydana gelmesiyle (ör. sosyal zaman çizelgeleri veya haber makaleleri) çok sık yapılan güncellemeler.

self.addEventListener('sync', function (event) {
  if (event.id == 'update-leaderboard') {
    event.waitUntil(
      caches.open('mygame-dynamic').then(function (cache) {
        return cache.add('/leaderboard.json');
      }),
    );
  }
});

Önbellek kalıcılığı

Kaynağınıza, istediği işlemleri yapması için belirli bir miktarda boş alan verilir. Bu boş alan, tüm kaynak depolama alanları arasında paylaşılır: (yerel) Depolama, IndexedDB, Dosya Sistemi Erişimi ve tabii ki Önbellekler.

Alacağınız tutar özel olarak belirtilmemiştir. Cihaz ve depolama koşullarına göre değişir. Ne kadar kazandığınızı şuradan öğrenebilirsiniz:

navigator.storageQuota.queryInfo('temporary').then(function (info) {
  console.log(info.quota);
  // Result: <quota in bytes>
  console.log(info.usage);
  // Result: <used data in bytes>
});

Ancak, tüm tarayıcı depolama alanlarında olduğu gibi, cihaz depolama alanı baskısı altında kalırsa tarayıcı verilerinizi özgürce atabilir. Maalesef tarayıcı, ne pahasına olursa olsun izlemek istediğiniz filmlerle gerçekten ilgilenmediğiniz oyunlar arasındaki farkı ayırt edemez.

Bu sorunu çözmek için StorageManager arayüzünü kullanın:

// From a page:
navigator.storage.persist()
.then(function(persisted) {
  if (persisted) {
    // Hurrah, your data is here to stay!
  } else {
   // So sad, your data may get chucked. Sorry.
});

Kullanıcının elbette izin vermesi gerekir. Bunun için Permissions API'yi kullanın.

Artık silme işleminin kontrolünün sizde olmasını beklediğimiz için kullanıcıyı bu akışın bir parçası haline getirmek önemlidir. Cihazları depolama baskısı altında kalıyorsa ve gerekli olmayan verilerin temizlenmesi sorunu çözmüyorsa kullanıcı, hangi öğeleri saklayacağına ve kaldıracağına karar vermelidir.

Bunun çalışması için işletim sistemlerinin, tarayıcıyı tek bir öğe olarak raporlamak yerine, depolama alanı kullanım dökümlerinde "dayanıklı" kaynakları platforma özgü uygulamaların eşdeğeri olarak değerlendirmesi gerekir.

Önerileri Sunma (isteklere yanıt verme)

Önbelleğe alma işlemini ne kadar yaptığınız önemli değildir. Service Worker, siz ne zaman ve nasıl uyguladığını bildirmediğiniz sürece önbelleği kullanmaz. Aşağıda, isteklerin ele alınmasına ilişkin birkaç kalıp verilmiştir:

Yalnızca önbellek

Yalnızca önbellek.
Yalnızca önbellek.

Şunlar için idealdir:Sitenizin belirli bir "sürümü" için statik olduğunu düşündüğünüz her şey. Bunları yükleme etkinliğinde önbelleğe almış olmanız gerekir. Böylece, bu bilgilerin nerede olduğuna güvenebilirsiniz.

self.addEventListener('fetch', function (event) {
  // If a match isn't found in the cache, the response
  // will look like a connection error
  event.respondWith(caches.match(event.request));
});

Bu durumu genelde özel olarak ele almanız gerekmese de Önbellek, ağa geri dönüş ile bu konuyu ele alır.

Yalnızca ağ

Yalnızca ağ.
Yalnızca ağ.

Şunlar için idealdir:Analiz ping'leri ve GET olmayan istekler gibi çevrimdışı eşdeğeri olmayan şeyler.

self.addEventListener('fetch', function (event) {
  event.respondWith(fetch(event.request));
  // or simply don't call event.respondWith, which
  // will result in default browser behavior
});

Bu durumu genelde özel olarak ele almanız gerekmese de Önbellek, ağa geri dönüş ile bu konuyu ele alır.

Önbellek, ağa geri dönülüyor

Önbellek, ağa geri dönüyor.
Önbellek, ağa geri dönüyor.

Şunlar için idealdir:Önce çevrimdışı derleme. Bu tür durumlarda isteklerin çoğunu bu şekilde ele alırsınız. Diğer kalıplar, gelen isteğe bağlı olarak istisnalar olacaktır.

self.addEventListener('fetch', function (event) {
  event.respondWith(
    caches.match(event.request).then(function (response) {
      return response || fetch(event.request);
    }),
  );
});

Bu, önbellekteki öğeler için "yalnızca önbellek" davranışını ve önbelleğe alınmamış her şey için "yalnızca ağ" davranışını (önbelleğe alınamadığı için GET olmayan tüm istekleri içerir) verir.

Önbellek ve ağ yarışı

Önbellek ve ağ yarışı.
Önbellek ve ağ yarışı.

Şunlar için idealdir:Yavaş disk erişimine sahip cihazlarda performans peşinde olduğunuz küçük öğeler.

Eski sabit diskler, virüs tarayıcıları ve daha hızlı internet bağlantılarının bazı kombinasyonlarıyla ağdan kaynak almak, diske gitmekten daha hızlı olabilir. Ancak, içerik kullanıcı cihazındayken ağa gitmek bir veri israfı olabilir. Bu nedenle bunu göz önünde bulundurun.

// Promise.race is no good to us because it rejects if
// a promise rejects before fulfilling. Let's make a proper
// race function:
function promiseAny(promises) {
  return new Promise((resolve, reject) => {
    // make sure promises are all promises
    promises = promises.map((p) => Promise.resolve(p));
    // resolve this promise as soon as one resolves
    promises.forEach((p) => p.then(resolve));
    // reject if all promises reject
    promises.reduce((a, b) => a.catch(() => b)).catch(() => reject(Error('All failed')));
  });
}

self.addEventListener('fetch', function (event) {
  event.respondWith(promiseAny([caches.match(event.request), fetch(event.request)]));
});

Ağ önbelleğe alınıyor

Ağ önbelleğe alınıyor.
Ağ, önbelleğe alınıyor.

Şunlar için idealdir:Sitenin "sürümü" dışında, sık sık güncellenen kaynaklar için hızlı bir düzeltme. Örneğin makaleler, avatarlar, sosyal medya takvimi ve oyun liderlerine ait panolar.

Bu, çevrimiçi kullanıcılara en güncel içeriği sunduğunuz, çevrimdışı kullanıcıların ise önbelleğe alınan daha eski bir sürüm alacağı anlamına gelir. Ağ isteği başarılı olursa önbellek girişini güncellemek isteyebilirsiniz.

Ancak bu yöntemin dezavantajları vardır. Kullanıcı kesintili veya yavaş bir bağlantı yaşıyorsa cihazında tamamen kabul edilebilir içeriğe erişmeden önce ağın çökmesini beklemek gerekir. Bu son derece uzun sürebilir ve can sıkıcı bir kullanıcı deneyimidir. Daha iyi bir çözüm için bir sonraki kalıp olan Önbellekten sonra ağ'a bakın.

self.addEventListener('fetch', function (event) {
  event.respondWith(
    fetch(event.request).catch(function () {
      return caches.match(event.request);
    }),
  );
});

Önbellek ve ardından ağ

Önbellek, ardından ağ.
Önbelleğe alın, ardından ağ oluşturun.

Şunlar için idealdir:Sık sık güncellenen içerik. Örneğin makaleler, sosyal medya zaman çizelgeleri, oyunlar. Skor tabloları.

Bu, sayfanın biri önbelleğe, diğeri ağa yönelik olmak üzere iki istekte bulunmasını gerektirir. Buradaki amaç, önce önbelleğe alınan verileri göstermek, ardından ağ verileri geldiğinde sayfayı güncellemektir.

Bazen yeni veriler geldiğinde (ör. oyun skor tablosu) mevcut verileri değiştirebilirsiniz, ancak bu daha büyük içerik parçalarıyla kesintiye neden olabilir. Temel olarak kullanıcının okuduğu veya etkileşime girdiği bir şeyi "kaybolmasın".

Twitter, yeni içeriği eski içeriğin üzerine ekler ve kaydırma konumunu kullanıcının kesintisini olmayacak şekilde ayarlar. Twitter, içerik için çoğunlukla doğrusal bir sıralamayı koruduğu için bu mümkündür. İçeriği mümkün olduğunca hızlı bir şekilde ekranda gösterip güncel içeriği gelir gelmez göstermek için heyecan uyandırmak için eğitilen bu kalıbı kopyaladım.

Sayfadaki kod:

var networkDataReceived = false;

startSpinner();

// fetch fresh data
var networkUpdate = fetch('/data.json')
  .then(function (response) {
    return response.json();
  })
  .then(function (data) {
    networkDataReceived = true;
    updatePage(data);
  });

// fetch cached data
caches
  .match('/data.json')
  .then(function (response) {
    if (!response) throw Error('No data');
    return response.json();
  })
  .then(function (data) {
    // don't overwrite newer network data
    if (!networkDataReceived) {
      updatePage(data);
    }
  })
  .catch(function () {
    // we didn't get cached data, the network is our last hope:
    return networkUpdate;
  })
  .catch(showErrorMessage)
  .then(stopSpinner);

Hizmet Çalışanındaki Kod:

Her zaman ağa gitmeli ve ilerledikçe bir önbelleği güncellemelisiniz.

self.addEventListener('fetch', function (event) {
  event.respondWith(
    caches.open('mysite-dynamic').then(function (cache) {
      return fetch(event.request).then(function (response) {
        cache.put(event.request, response.clone());
        return response;
      });
    }),
  );
});

Heyecanla ilgili eğitimde bu sorunun üstesinden gelmek için getirme yerine XHR işlevini kullanarak ve Service Worker'a sonucu nereden alacağını (sayfa kodu, Service Worker kodu) bildirmek için Accept üstbilgisini kötüye kullandım.

Genel yedek

Genel yedek.
Genel yedek.

Önbellekten ve/veya ağdan bir şey sunamazsanız genel bir yedek sağlamak isteyebilirsiniz.

Şunlar için idealdir:Avatarlar, başarısız POST istekleri ve "Çevrimdışıyken kullanılamaz" sayfası gibi ikincil görüntüler.

self.addEventListener('fetch', function (event) {
  event.respondWith(
    // Try the cache
    caches
      .match(event.request)
      .then(function (response) {
        // Fall back to network
        return response || fetch(event.request);
      })
      .catch(function () {
        // If both fail, show a generic fallback:
        return caches.match('/offline.html');
        // However, in reality you'd have many different
        // fallbacks, depending on URL and headers.
        // Eg, a fallback silhouette image for avatars.
      }),
  );
});

Yedeklediğiniz öğe büyük olasılıkla bir yükleme bağımlılığı olacaktır.

Sayfanız bir e-posta yayınlıyorsa hizmet çalışanınız e-postayı bir IndexedDB "giden kutusunda" depolamaya devam edebilir ve sayfanın, gönderme işleminin başarısız olduğunu ancak verilerin başarılı bir şekilde tutulduğunu belirterek yanıt verebilir.

Hizmet çalışanı tarafı şablonu

ServiceWorker tarafı şablonları.
ServiceWorker tarafı şablonları.

Şunlar için idealdir:Sunucu yanıtının önbelleğe alınamayacağı sayfalar.

Sayfaların sunucuda oluşturulması işlemleri hızlandırır ancak bu, önbellekte anlam ifade etmeyebilecek durum verilerinin (ör. "... olarak giriş yapıldı") eklenmesi anlamına gelebilir. Sayfanız bir Service Worker tarafından kontrol ediliyorsa bunun yerine JSON verilerini bir şablonla birlikte istemeyi ve şablonu oluşturmayı tercih edebilirsiniz.

importScripts('templating-engine.js');

self.addEventListener('fetch', function (event) {
  var requestURL = new URL(event.request.url);

  event.respondWith(
    Promise.all([
      caches.match('/article-template.html').then(function (response) {
        return response.text();
      }),
      caches.match(requestURL.path + '.json').then(function (response) {
        return response.json();
      }),
    ]).then(function (responses) {
      var template = responses[0];
      var data = responses[1];

      return new Response(renderTemplate(template, data), {
        headers: {
          'Content-Type': 'text/html',
        },
      });
    }),
  );
});

Bir araya getirme

Bu yöntemlerden biriyle sınırlı değilsiniz. Aslında, istek URL'sine bağlı olarak bunların çoğunu kullanırsınız. Örneğin, eğitilmiş heyecanlı içerik stratejisi şunları kullanır:

İsteğe bakıp ne yapacağınıza karar vermeniz yeterli:

self.addEventListener('fetch', function (event) {
  // Parse the URL:
  var requestURL = new URL(event.request.url);

  // Handle requests to a particular host specifically
  if (requestURL.hostname == 'api.example.com') {
    event.respondWith(/* some combination of patterns */);
    return;
  }
  // Routing for local URLs
  if (requestURL.origin == location.origin) {
    // Handle article URLs
    if (/^\/article\//.test(requestURL.pathname)) {
      event.respondWith(/* some other combination of patterns */);
      return;
    }
    if (/\.webp$/.test(requestURL.pathname)) {
      event.respondWith(/* some other combination of patterns */);
      return;
    }
    if (request.method == 'POST') {
      event.respondWith(/* some other combination of patterns */);
      return;
    }
    if (/cheese/.test(requestURL.pathname)) {
      event.respondWith(
        new Response('Flagrant cheese error', {
          status: 512,
        }),
      );
      return;
    }
  }

  // A sensible default pattern
  event.respondWith(
    caches.match(event.request).then(function (response) {
      return response || fetch(event.request);
    }),
  );
});

...anında bir resim oluyor.

Kredi

...sevimli simgeler için:

  • buzzyrobot tarafından sunulan Code
  • Takvim: Scott Lewis
  • Ağ: Ben Rizzo
  • SD - Thomas Le Bas
  • iconmind.com tarafından sunulan CPU
  • Trasnik tarafından oluşturulan Çöp Kutusu
  • @daosme tarafından gönderilen bildirim
  • Mister Pixel Layout
  • Cloud - P.J. Onori

Ayrıca, "yayınla" düğmesine basmadan önce birçok uğultu hatası yakaladığı için Jeff Posnick'e de teşekkür ederim.

Daha fazla bilgi