西西河

主题:【原创】PWA,边学边问边用 -- 铁手

共:💬11 🌺59
全看分页树展 · 主题 跟帖
家园 【攻关】Service worker缓存功能,对比和疑问

多谢几位回复和讨论,@tom,@骆筱,克雷。我花了一段时间看文档和代码,并且试着弄了个 service worker 代码看效果,有一些疑问希望大家讨论,帮助解疑。

这里先关注 service worker 的缓存功能,其他功能另外会开分枝讨论。

先看一下目前浏览器的缓存功能,再对照 service worker 的缓存功能,然后试图发现 service worker 的优越性。

目前浏览器的缓存功能:

访问一个页面的时候,浏览器可以有两种方式来获得内容。一是在本地缓存找,二是通过网络到服务器去拿。

浏览器会首先去到本地缓存里找,有的话或者就直接显示了,或者就去问一下服务器要不要更新,没有的话通过网络从服务器来获取。缓存有没有,根据服务器响应得设定来决定。可以通过 Cache-control 或者是 ETag。一般来说,从本地获取总是比通过网络获取来得快。

为了提高网站性能,一般就是在服务器对各个具体页面设定缓存控制,包括能不能被 CDN 这类代理缓存。

Service Worker 的缓存机制是在 javascript 代码中利用浏览器的一个新的缓存功能Cache Storage 来实现。比如浏览一个页面时,如果 service worker 从服务器获取内容,可以放到 Cache Storage 里,以后再访问这个页面的时候,就有可能通过 service worker 从 缓存里获得内容。也就是说,以前浏览器自动执行的这些缓存功能,现在需要自己写代码实现缓存的逻辑。好处在哪里,暂时看不出来,有一点优势可能是:浏览器缓存是所有网址共用,service woker操作的缓存是分别对应于各个网站域名,大概可以保证缓存空间足够。

理想的状态下,我可能希望做到这样的缓存机制:

服务器端根据页面特性,设置缓存限制:不缓存,缓存定时直接从缓存取,有缓存,但是问服务器有没有过时,过了取新的,否则取本地缓存。

浏览器干这些已经很在行了,service worker 要自己写代码来实现逻辑。

service worker 中怎么弄?是不是需要如下的做法?

1、 caches.match(cacheRequest);

如果没内容,则 走网络 fetch。

如果有内容,对返回查看 cache-control (怎么查看?),然后根据结果决定是不是去服务器取内容。如果不需要,内容直接显示。如果需要,则 走网络fetch。

2、fetch(fetchRequest);

fetch 返回的 response,新内容好说,显示并且缓存。有没有可能缓存中有内容,服务器返回的是 304 Not Modified 内容没有变更?需要检查返回的状态码么?还是说 fetch 本身就已经实现了这些缓存逻辑?只需要返回 fetch 的 response 就可以?

目前我试验了两种方式。

一种是先 fetch 并缓存,有错则通过缓存 match。我的理解是,有网情况下,和没有 service-work工作方式类似,但是每次都需要通过网络从服务器取,不能利用本地缓存快速响应。好处是无网的情况下,本地缓存内容可以显示出来。

还有一种是先 match ,有错则 fetch 并缓存。我的理解是,有网无网,有缓存就都有内容显示。有网的情况下,缓存也得不到更新,因为没有机会 fetch。如果缓存没内容,fetch 普通页面没问题,但是 ajax要取的页面首先返回网络超时,再来一次则有内容。是不是对 ajax 的页面请求需要

event.waitUntil(event.respondWith(....

顺便说一下,navigator.serviceWorker.register("/sw.js") 时候,它的作用范围在 service worker js 文件目录及以下子目录,可以设定更小的范围,但是不能设定更大的范围。比如 /aaa/sw.js 的作用范围没有办法设定到 /。我本来想集中这些到一个子目录然后作用到网站所有目录,直觉是对的,操作不能。这个规则不是那么直白,提个醒。

下面是测试 先网络取,本地缓存为后备的代码。怎么有效改为缓存为先,必要的话网络。

self.addEventListener('fetch', function(evt) {
 // Clone the request for fetch and cache
 // A request is a stream and can be consumed only once.
 var fetchRequest = evt.request.clone(),
 cacheRequest = evt.request.clone();
 if (evt.request.method === 'GET') {
 // Respond with content from fetch or cache
 evt.respondWith(
 // Try fetch
 fetch(fetchRequest)
 // when fetch is successful, we update the cache
 .then(
 function(response) {
 // A response is a stream and can be consumed only once.
 // Because we want the browser to consume the response,
 // as well as cache to consume the response, we need to
 // clone it so we have 2 streams
 var responseToCache = response.clone();
 // and update the cache
 caches
 .open(CACHE)
 .then(function(cache) {
 // Clone the request again to use it
 // as the key for our cache
 var cacheSaveRequest = evt.request.clone();
 cache.put(cacheSaveRequest, responseToCache);
 });
 // Return the response stream to be consumed by browser
 return response;
 }
 )
 // when fetch times out or fails
 .catch(
 function(err) {
 // Return the promise which
 // resolves on a match in cache for the current request
 // ot rejects if no matches are found
 return caches.match(cacheRequest);
 }
 )
 );
 }
});
关键词(Tags): #Service worker
全看分页树展 · 主题 跟帖


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河