关于前端:浏览器缓存机制介绍及前端优化方案

101次阅读

共计 3554 个字符,预计需要花费 9 分钟才能阅读完成。

背景

缓存是用来做性能优化的好货色,然而,如果用不好缓存,就会产生一系列问题:

  • 为什么我的页面显示的还是老版本
  • 为什么我的网页白屏
  • 请刷新下网页

以上问题大家或多或少都遇到过,归根结底是应用缓存的姿态不对,明天,咱们就来一起理解下浏览器是如何进行缓存的,以及咱们要怎么迷信的应用缓存

浏览器的缓存机制

1. 什么是浏览器缓存?

简略说,浏览器把 http 申请的资源保留到本地,供下次应用的行为,就是浏览器缓存

这里先记一个点:http 响应头,决定了浏览器会对资源采取什么样的缓存策略

2. 浏览器是读取缓存还是申请数据?

  • 用户第一次申请资源
  • 整个残缺流程

3. 缓存过程分类——强缓存 / 协商缓存

依据是否申请服务,咱们把缓存过程分为强缓存和协商缓存,也能够了解为必然通过的过程称为强缓存,如果强缓存没有,那在和服务器协商一下

强缓存

强缓存看的是响应头的 Expires 和 Cache-Control 字段

  • Expires 是老标准,它示意的是一个相对无效工夫,在该工夫之前则命中缓存,如果超过则缓存生效,并且,因为它是跟本地工夫(能够随便批改)做比拟,会导致缓存凌乱
  • Cache-Control 是新标准,优先级要高于 Expires,也是目前次要应用的缓存策略,字段是 max-age,示意的是一个绝对工夫,例如 Cache-Control: max-age=3600,代表着资源的有效期是 3600 秒。

其余配置

no-cache:须要进行协商缓存,发送申请到服务器确认是否应用缓存。

no-store:禁止应用缓存,每一次都要从新申请数据。

public:能够被所有的用户缓存,包含终端用户和 CDN 等两头代理服务器。

private:只能被终端用户的浏览器缓存,不容许 CDN 等中继缓存服务器对其缓存。

协商缓存

当强缓存没有命中的时候,浏览器会发送一个申请到服务器,服务器依据 header 中的局部信息来判断是否命中缓存。如果命中,则返回 304,通知浏览器资源未更新,可应用本地的缓存。

协商缓存看的是 header 中的 Last-Modified / If-Modified-Since 和 Etag / If-None-Match

缓存失效,返回 304,缓存生效,返回 200 和申请后果

Etag 优先级 Last-Modified 高

  • Last-Modified / If-Modified-Since

浏览器第一次申请一个资源的时候,服务器返回的 header 中会加上 Last-Modify,Last-modify 是一个工夫标识该资源的最初批改工夫。

当浏览器再次申请该资源时,request 的申请头中会蕴含 If-Modify-Since,该值为缓存之前返回的 Last-Modify。服务器收到 If-Modify-Since 后,依据资源的最初批改工夫判断是否命中缓存,命中返回 304 应用本缓存,否则返回 200 和申请最新资源。

  • Etag / If-None-Match

etag 是更为谨严的校验,个别状况下应用工夫测验曾经足够,但咱们设想一个场景,如果咱们在短暂工夫内批改了服务端资源,而后又迅速的改回去,实践上这种状况本地缓存还是能够持续应用的,这就是 etag 诞生的场景。

应用 etag 时服务端会对资源进行一次相似 hash 的操作取得一个标识(内容不变标识不变),并返回给客户端。

再次申请时客户端会在 If-None-Match 带上 etag 的值给服务端进行比照验证,如果命中返回 304 应用缓存,否则从新申请资源。

注:因为 e-atg 服务端计算会有额定开销,所以性能较差

扩大:DNS 缓存与 CDN 缓存

DNS 缓存

咱们在网上所有的通信行为都须要 IP 来进行连贯,DNS 解析是指通过域名获取相应 IP 地址的过程。

基本上有 DNS 的中央就有缓存,查问程序如下:

个别咱们日常会接触到的就是有时内网域名拜访须要批改本地 host 映射关系,或者某些迷信上网的状况,能够通过批改本地 host 来失常拜访网址

CDN 缓存

CDN 缓存从加重根服务的散发压力和缩短物理的传输间隔(跨地区拜访)上 2 个层面对资源拜访进行优化。

CDN 节点解决了跨运营商和跨地区拜访的问题,拜访延时大大降低。

大部分申请在 CDN 边缘节点实现,CDN 起到了分流作用,加重了源服务器的负载。

个别 CDN 服务都由运营商提供,咱们只须要理解如何验证 CDN 是否失效即可

  • 查看域名是否配置了 CDN 缓存

    ping {{域名}} 会看到转向了其余地址(alikunlun)

    例如:ping customer.kukahome.com

  • 查看咱们的页面资源是否命中 CDN 缓存

通过查看相应头有 X-cache:HIT 字段,则命中 CDN 缓存,留神这里名称并不固定,但个别都会有 HIT 标识,如果是 MISS 或 None 之类的,则没有命中缓存

前端针对缓存部署优化计划

构建演进

构建方面优化的核心思想是如何更优,更疾速的加载资源,以及如何保障资源的新鲜度

这个优化过程也分为几个阶段,有些其实曾经不实用当初的场景,但也能够理解下

  • 晚期的图标合并雪碧图(sprite),多脚本文件整顿到一个文件:目标是通过缩小碎片化的申请数量来减速资源加载(相干知识点是浏览器个别最多只反对 6 个并发申请,同一时间申请数量须要管制在正当范畴)

    • 当初雪碧图已根本被 iconfont 代替,js 加载更多采纳分模块异步加载,而不是一味合并
  • 随着 web 利用的推广和浏览器缓存技术的遍及,前端缓存问题也随着而来,最常见的就是服务端资源变了,然而客户端资源始终无奈更新,这个阶段工程师们想了很多计划。

    • 打包时在动态资源门路上加上 “?v=version” 或者应用工夫戳来给资源文件命名
    • 跟 modified 缓存有点像,因为工夫戳并不能辨认出文件内容是否变动,所以有了起初的 hash 计划,实践上 hash 进去的文件只有内容不变,文件名就不变,大大提高了缓存的使用寿命,也是古代罕用打包工具的默认配置
  • 而后,重点来了,以上咱们对 html 文件里链接的资源做了一系列优化,然而 html 自身也是一种动态资源,并且,客户在拜访页面时是不会带上所谓的工夫戳或者版本号的,导致了很多时候尽管服务端资源更新了,然而客户端还是用老的 html 文本发动申请,这个时候就会导致各种各样的问题了,包含但不限于 白屏,展示的旧版本页面等等

    • 为了解决这个问题,目前支流的解决方案是不对 html 进行缓存(个别单页利用 html 文件较小,大的是 js),只对 js,css 等动态文件进行本地缓存
    • 那么,如何让浏览器不缓存 html 呢,目前都是通过设置 Cache-Control实现,有前端计划和后端计划,危险提醒,前端计划很不靠谱,后端很多默认配置会笼罩前端计划,能够做理解,生产中请应用后端配置。

      通过 html 标签设置 cache-control

        <meta http-equiv="Pragma" content="no-cache" />  // 旧协定
        <meta http-equiv="Expires" content="0" /> // 旧协定
        <meta http-equiv="Cache-Control" content="no-cache" /> // 目前支流

部署配置

目前支流的前端部署形式都是应用 nginx,咱们来看看 nginx 如何禁用 html 的缓存

location / {
    root **;  
    # 配置页面不缓存 html 和 htm 结尾的文件
    if ($request_filename ~* .*.(?:htm|html)$) 
    {add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";}
    index  index.html index.htm;
}
  • Private 会影响到 CDN 缓存命中率,但自身 CDN 缓存也会存在版本问题,量不大的状况下也能够禁掉
  • No-cache 能够应用缓存,然而应用前必须到服务端验证,能够是 no-cache,也能够是 max-age=0
  • No-store 齐全禁用缓存
  • Must-revalidate 与 no-cache 相似,强制到服务端验证,作用于一些非凡场景,例如发送了校验申请,但发送失败了之类
  • Proxy-revalidate 与下面相似,要求代理缓存服务验证有效性

以上配置能够跟据我的项目须要灵便配置,思考到浏览器对缓存协定反对会有些许差别,只是想简略粗犷禁用 html 缓存全上也没有关系,并不会有特地大影响,除非非凡场景须要调优时须要关注。

资源压缩

都讲到这了,前端构建优化还有一个罕用的就是 Gzip 资源压缩,能够极大减小资源包体积,前端个别构建工具都有插件反对,须要留神的是也须要 nginx 做配置能力失效

http {
    gzip_static on;
    gzip_proxied any;
}

如果失效了,响应头里能够看到 content-encoding: gzip

正文完
 0