Home > OS >  Intercept fetch for the first time but not afterwards using serviceWorker
Intercept fetch for the first time but not afterwards using serviceWorker

Time:09-11

Need some guidance here with service worker.

When the service worker is installed, it caches the assets. On next reload, when any request is made, it is intercepted by service worker, which first checks in cache, if it isn't found, then we make a network call. But this second network call is again being intercepted by service worker and thus it has turned into an infinite loop.

I don't want the next fetch call, to be intercepted again. I hope I'm able to explain the issue here.

Here is the serviceWorker.js

const cacheVersion = "v11";
self.addEventListener('install',(event)=>{
    self.skipWaiting();
    event.waitUntil(caches.open(cacheVersion).then((cache)=>{
        cache.addAll([
            '/',
            '/index.html',
            '/style.css',
            '/images/github.png',
        ])
        .then(()=>console.log('cached'),(err)=>console.log(err));
    }))
})

self.addEventListener('activate',event=>{
    event.waitUntil(
        (async ()=>{
            const keys = await caches.keys();
            return keys.map(async (cache)=>{
                if(cache !== cacheVersion){
                    console.log("service worker: Removing old cache: " cache);
                    return await caches.delete(cache);
                }
            })
        })()
    )
})

const cacheFirst = async (request) => {
    try{
        const responseFromCache = await caches.match(request);
        if (responseFromCache) {
        return responseFromCache;
        }
    }
    catch(err){
        return fetch(request);
    }
    return fetch(request);
};

self.addEventListener("fetch", (event) => {
    event.respondWith(cacheFirst(event.request));
});

CodePudding user response:

The reason here is your cacheFirst, it's a bit wrong. What do we want to do inside it (high-level algorithm) ? Should be something like this, right?

  • check cache and if match found - return
  • otherwise, fetch from server, cache and return
  • otherwise, if network failed - return some "dummy" response
const cacheFirst = async (request) => {
  
  // First try to get the resource from the cache
  const responseFromCache = await caches.match(request);
  if (responseFromCache) {
    return responseFromCache;
  }

  // Next try to get the resource from the network
  try {
    const responseFromNetwork = await fetch(request);
    // response may be used only once
    // we need to save clone to put one copy in cache
    // and serve second one
    putInCache(request, responseFromNetwork.clone());
    return responseFromNetwork;
  } catch (error) {
    // well network failed, but we need to return something right ?
    return new Response('Network error happened', {
      status: 408,
      headers: { 'Content-Type': 'text/plain' },
    });
  }
};

This is not ready-to-use solution !!! Think of it as a pseudo-code, for instance you might need to impl putInCache first.

  • Related