最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

caching - Javascript service worker: Fetch resource from cache, but also update it - Stack Overflow

programmeradmin1浏览0评论

I'm using a service worker on chrome to cache network responses. What I intend to do when a client requests a resource:

Check cache - If it exists, return from cache, but also send a request to server and update cache if file differs from the cached version. If cache does not have it, send a request for it to the server and then cache the response.

Here's my current code for doing the same:

self.addEventListener('fetch', function (event) {
    var requestURL = new URL(event.request.url);
    var freshResource = fetch(event.request).then(function (response) {
        if (response.ok && requestURL.origin === location.origin) {
            // All good? Update the cache with the network response
            caches.open(CACHE_NAME).then(function (cache) {
                cache.put(event.request, response);
            });
        }
        // Return the clone as the response would be consumed while caching it
        return response.clone();
    });
    var cachedResource = caches.open(CACHE_NAME).then(function (cache) {
        return cache.match(event.request);
    });
    event.respondWith(cachedResource.catch(function () {
        return freshResource;
    }));
});

This code does not work as it throws an error:

The FetchEvent for url resulted in a network error response: an object that was not a Response was passed to respondWith().

Can anyone point me in the right direction?

I'm using a service worker on chrome to cache network responses. What I intend to do when a client requests a resource:

Check cache - If it exists, return from cache, but also send a request to server and update cache if file differs from the cached version. If cache does not have it, send a request for it to the server and then cache the response.

Here's my current code for doing the same:

self.addEventListener('fetch', function (event) {
    var requestURL = new URL(event.request.url);
    var freshResource = fetch(event.request).then(function (response) {
        if (response.ok && requestURL.origin === location.origin) {
            // All good? Update the cache with the network response
            caches.open(CACHE_NAME).then(function (cache) {
                cache.put(event.request, response);
            });
        }
        // Return the clone as the response would be consumed while caching it
        return response.clone();
    });
    var cachedResource = caches.open(CACHE_NAME).then(function (cache) {
        return cache.match(event.request);
    });
    event.respondWith(cachedResource.catch(function () {
        return freshResource;
    }));
});

This code does not work as it throws an error:

The FetchEvent for url resulted in a network error response: an object that was not a Response was passed to respondWith().

Can anyone point me in the right direction?

Share Improve this question asked Sep 7, 2016 at 7:39 AwolAwol 3532 silver badges13 bronze badges 5
  • 2 catch actually returns a Promise object. you might want to attach a then handler to cachedResource and call respondWith within that – thefourtheye Commented Sep 7, 2016 at 7:41
  • @thefourtheye - Don't you mean, call event.respondWith inside then for cache.match? That will be an error, since fetch will be resolved by the time caches.open is executed. I made the change and ran the code to find this error. – Awol Commented Sep 7, 2016 at 7:47
  • @Awol: How so? Presumably the cache opens and matches faster than the fetch? – Bergi Commented Sep 7, 2016 at 10:17
  • @Bergi - Fetch sure takes more time than the cache open, but event.respondWith is fired inside caches.open, which is triggered much later after the fetch handler ends – Awol Commented Sep 7, 2016 at 10:22
  • Okay, guys. I fixed my issue and posted the answer. Thank you so much for the ideas! – Awol Commented Sep 7, 2016 at 10:28
Add a ment  | 

1 Answer 1

Reset to default 7

Okay, I fiddled with the code after people pointed out suggestions (thank you for that) and found a solution.

self.addEventListener('fetch', function (event) {
    var requestURL = new URL(event.request.url);
    var freshResource = fetch(event.request).then(function (response) {
        var clonedResponse = response.clone();
        // Don't update the cache with error pages!
        if (response.ok) {
            // All good? Update the cache with the network response
            caches.open(CACHE_NAME).then(function (cache) {
                cache.put(event.request, clonedResponse);
            });
        }
        return response;
    });
    var cachedResource = caches.open(CACHE_NAME).then(function (cache) {
        return cache.match(event.request).then(function(response) {
            return response || freshResource;
        });
    }).catch(function (e) {
        return freshResource;
    });
    event.respondWith(cachedResource);
});

The entire problem originated in the case where the item is not present in cache and cache.match returned an error. All I needed to do was fetch actual network response in that case (Notice return response || freshResource)

This answer was the Aha! moment for me (although the implementation is different): Use ServiceWorker cache only when offline

发布评论

评论列表(0)

  1. 暂无评论