HTTP缓存 && Service Worker

温馨提示
本文只是下面两篇文章
HTTP缓存
Caching best practices & max-age gotchas
的阅读理解。如有错误请不吝赐教!

前段时间看了Service Worker,今天看了HTTP缓存,既然都是缓存,那么它们之间必定就有联系。
HTTP缓存的内容不多,总结成了一张思维导图,具体可以看这篇文章:
HTTP缓存

HTTP缓存

还有文章里一张很干货的图,什么时候用什么缓存策略:
HTTP缓存策略

关于缓存策略还可以参考这篇文章:
Caching best practices & max-age gotchas
文章主要思想如下:

  1. 不变的内容,用大的max-age,比如Cache-Control: max-age=31536000,当文件发生修改,可以通过同步更新文件名(比如,style-v1.css , style-v2.css)的方式在强制更新缓存。
    这种方法不适用于博客类的网页,因为博文的url无法版本化。
  2. 经常改变的内容,每次请求都要向服务器验证其内容没变,Cache-Control: no-cache
  3. 适当使用max-age会有效减轻服务器压力,但有时把max-age用在经常改变的内容上可能会有很严重的后果。
    举个例子,现在HTTP缓存了index.html, style.css, script.js,在新鲜期内,缓存器丢失了style.css,而服务器刚好又更新了这三个文件。
    现在我请求这三个文件,缓存器会返回缓存的index.html, script.js,因为style.css丢了,所以他要向服务器请求新的css文件。
    那么,现在,我得到了旧的html,js文件,新的css文件,会出现什么情况呢?
    整张页面的样式可能全乱掉了。
    更可怕的是,因为三者的max-age是一样的,那么缓存器请求了新的css文件,css文件的到期时间和html,js文件就变得不同步了!这样的连锁反应导致的后果就是,以后缓存器中的style.cssindex.html, script.js可能会一直保持早不兼容的状态。
  4. 如何解决这个问题呢?一种方法是用户刷新页面,因为刷新页面会绕过max-age,向服务器重新验证内容是否为最新。但是这么做会降低用户对网站的好感度。
  5. 第二种方法是和Service Worker合作。

终于进入正题了~~!
我们可能会想要用SW来代替HTTP缓存,比如现在写一个这样的sw.js

const version = '2';

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(`static-${version}`)
      .then(cache => cache.addAll([
        '/styles.css',
        '/script.js'
      ]))
  );
});

self.addEventListener('activate', event => {
  // …delete old caches…
});

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

这段代码说,每次更新SW,SW在install阶段中,会缓存/styles.css, /script.js两个文件,之后会捕获用户的网络请求,先去找缓存里有没有对象的响应,没有的话再走正常的网络流程。

但是很尴尬的是,也许你已经从前面的“正常的网络流程”的字里行间看出来了,如果SW发送了一个网络请求,请求也会经过缓存服务器,缓存服务器很可能会返回缓存的文件。也就是说,我们还是会得到不兼容的版本。

同样的道理,SW在install阶段缓存的这两个文件,也很有可能是不兼容的旧版本。

那我们要怎么避免这种情况?一个办法是让SW每次发送的url都不一样,这样就绕过了HTTP缓存了。

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(`static-${version}`)
      .then(cache => Promise.all(
        [
          '/styles.css',
          '/script.js'
        ].map(url => {
          // url中添加一个随机数
          return fetch(`${url}?${Math.random()}`).then(response => {
            // fail on 404, 500 etc
            if (!response.ok) throw Error('Not ok');
            return cache.put(url, response);
          })
        })
      ))
  );
});

有一些浏览器已经支持了Request接口的cache选项,可以直接这么写:

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(`static-${version}`)
      .then(cache => cache.addAll([
        new Request('/styles.css', { cache: 'no-cache' }),
        new Request('/script.js', { cache: 'no-cache' })
      ]))
  );
});

我们似乎已经解决了问题,但是,用SW代替HTTP缓存可行吗?‘
看一下SW的兼容性,是不是泪流满面?因为这种方案只能解决支持SW的浏览器的问题。

更好的方法是两者结合。

在HTTP缓存中,把根页面的缓存机制设为:no-cache,css,js文件用版本号控制变更,然后使用max-age=...的缓存策略。每次我们更新css或者js文件,文件名也会改变。

使用下面的sw.js代码:

const version = '23';

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(`static-${version}`)
      .then(cache => cache.addAll([
        '/',
        '/script-f93bca2c.js',
        '/styles-a837cb1e.css',
        '/cats-0e9a2ef4.jpg'
      ]))
  );
});

每次SW更新时,都会触发一次对根页面的请求。而css,js文件只有在文件名改变时,才会打扰远程服务器。

如此,我们避免了版本不兼容的问题,也有效的节省了带宽。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容