主题:【原创】PWA,边学边问边用 -- 铁手
多谢几位回复和讨论,@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); } ) ); } });
- 相关回复 上下关系8
🙂【原创】PWA,边学边问边用 25 铁手 字4337 2018-10-25 18:14:36
🙂【攻关】Service worker缓存功能,对比和疑问
🙂看了更多文档,自己也做了一些测试 铁手 字631 2018-11-01 00:45:58
🙂这儿有两本本电子书,可以参考一下 1 透明 字519 2018-11-01 22:01:24
🙂感觉就是chrome extension换了个外套 3 克雷 字249 2018-10-26 12:21:40
🙂我理解PWA是一个设计模式 design pattern 2 透明 字463 2018-11-01 22:10:38
🙂目前看来这个PWA会持续下去 2 铁手 字641 2018-10-28 14:51:07
🙂说说我的理解 8 透明 字1538 2018-10-25 23:42:53