浏览器性能优化

在工作中会碰到各种各样性能问题,本文根据自己在工作中的实践并且结合各方面了解到的知识形成,可能不会谈到具体的实现,只描述可能的方向,包括如下:js/css加载、第三方js加载、CDN、图片懒加载、首屏渲染、react性能优化、webpack打包、浏览器缓存、预加载、预解析

一、浏览器缓存

缓存可以显著提高浏览器加载速度。

通常使用的缓存有两种:强缓存、协商缓存

浏览器使用缓存过程如下:

  1. 浏览器每次发器请求前,都会在浏览器缓存中查找该请求的结果和缓存标识;如果找不到则发器请求,找到通过ExpiresCache-Control验证是否命中强缓存,是则直接使用,否则发起请求

  2. 若没命中强缓存,在请求的头中会加上If-Modified-SinceIf-None-Match分别对应相应头中的Last-ModifiedETag,服务器会判断资源是否命中协商缓存(资源是否被修改),没有则返回304,浏览器使用本地资源

  3. 若资源被修改,重新返回新的资源,浏览器根据新的返回重新协商缓存。

强缓存

强缓存需在服务器配置ExpiresCache-Control

  • Expires

    Expires是http1.0提出的,表示一个绝对时间,如果修改了本地时间,会造成缓存时间失效。

    Expires: Thu, 01 Aug 2019 16:31:38 GMT
    
  • Cache-Control

    cache-control 是http1.1提出的,表示相对时间

    cache-control: max-age=31536000
    

    可选值如下:

    • public:客户端和中间代理服务器均可缓存,所有用户缓存
    • private:只有客户端可以缓存(私有缓存)
    • no-cache: 缓存到本地,但是每次都会发请求到服务器进行验证
    • no-store: 客户端不缓存
    • must-revalidate: 在本地缓存没过期前使用本地缓存,过期了就从服务器获取
    • max-age: 表示资源在多少秒后过期
    • s-max-age: 同样表示过期时间,不过是表示中间代理服务器的过期时间

强缓存会直接返回200(disk cache)或200(disk cache)

协商缓存

协商缓存会在请求头中加上If-Modified-SinceIf-None-Match

  • If-Modified-Since

    If-Modified-Since与Last-Modified对应,表示资源从Last-Modified时间后是否经过修改,精确到秒s,一秒内经过多次修改则无法检测到,在本地打开缓存的文件同样会更新Last-Modified,所以需要配合ETag

  • If-None-Match

    ETag是一个资源的唯一标识,每次修改后得到的ETag值都是不同的

区别
  1. Etag优先级比Last-Modified高
  2. 如果资源更新了,但内容没变,Last-Modified会变,ETag不会
  3. Last-Modified是s级别的,所以在单位时间内修改多次无法检测到

index.html可以使用协商缓存、js/css可以使用强缓存

二、第三方js加载

在项目中会用到第三方服务,比如gtag,可以在页面最后加载并使用异步加载,防止加载过慢阻塞页面渲染,

异步加载:async、defer

  • async: 加载时不会阻塞页面渲染,加载完成后立即执行,可能在DOMContentLoaded之前也可能在之后,但一定在load事件之前执行。
<script src="https://www.googletagmanager.com/gtag/js?id=UA-xxxxxxx" async></script>
  • defer:加载时不阻塞页面渲染,在html渲染完成后执行,然后触发DOMContentLoad事件,如果有多个defer标识的脚本,加载完成后将按照其在html中的顺序执行。

    对于多个有前后顺序要求的异步脚本,使用defer,否则使用async

三、CDN

CDN即内容分发网络,将服务器上的静态网络分发到多台服务器上,用户访问时从最近的服务器上获取,减少因分布、带宽和服务器性能的带来的影响。

CDN好处
  1. 提高网站打开速度,速度不好,用户容易流失
  2. 有利于google搜索,google将网站的打开速度作为搜索排名的一个重要标志,使用CDN后速度变快,用户跳出率减少
  3. 减少宕机风险。没有CDN时,当同一时间用户访问量太大,容易造成宕机;使用CDN之后减少宕机风险,提高网站访问量
  4. 减少托管成本。公司如果自己使用VPS,会付出更高的成本,使用CDN可以减少成本,CDN服务器不需要自己维护,文件储存在多台机器上,可以降低运维和流量成本。
CDN适用场景
  1. 互联网

使用场景:

  1. 由于国外的客户在访问公司网站时速度较慢,所以换成了CDN可以显著提升加载效率,目前国内服务也上传至CDN网络
  2. 图片属于比较大的文件也需要使用CDN

国内的CDN服务商很多,我们目前使用七牛

四、图片懒加载

在图片很少的情况下不会对网页造成影响,图片非常多时会明显感觉到页面加载耗时比较长,用户的等待时间就变长,降低用户的体验感。

所以在产品列表页面使用图片懒加载,可以使用IntersectionObserver或者通过滚动事件监听元素是否出现在视口。目前使用IntersectionObserver来进行图片懒加载,具体实现可看官网文档mdn

优点

  • 提升用户体验:减少页面加载时间
  • 减少无用资源加载:减少服务器压力和流量,用户可能不需要滚动到图片所在位置
  • 防止加载图片过多阻塞js文件加载

五、首屏渲染

在打开网站时,会出现一段时间的空白页面,对于spa应用来说主要由两部分时间组成:index.html加载和渲染、js加载和执行,spa应用是在js加载执行之后才把相应路由的html渲染出来,在此之前页面都是空白。优化主要从index.html入手。

  1. 添加首屏loading,在index.html中添加加载动画,让用户知道页面正在加载而不是卡住了。使用webpack打包时可以通过HtmlWebpackPlugin注入相应的html和css,打包时用ejs渲染到首页中。
  2. 进行SSR服务器端渲染,可以使用next.js来做

因为我们是2B的项目,所以采用了第一种方式。是2C项目的话,采用ssr方式比较好,ssr对页面的SEO有一定好处。

六、react性能优化

  1. 展示型组件使用PureComponet避免没用的渲染,PureComponent自动进行了浅比较,对于多层嵌套的数据,可以使用Immutable.js

  2. 业务组件使用ShouldComponentUpdate,手动判断组件是否需要渲染

  3. 列表通过map遍历时,需要加上key标识数据的唯一性,key必须是唯一的数据,不推荐使用index来作为key。

  4. class组件是通过new来生成实例来调用render方法的,function组件只是函数调用,所以多使用函数式组件。

  5. class组件方法的绑定:

    1. 直接在dom中

      <div onClick={this.handleClick.bind(this)}></div>
      

      在每次render的时候都会重新绑定,产生新的韩式

    2. 使用箭头函数

      handleClick = () => {}
      <div onClick={this.handleClick}></div>
      

      箭头函数不会作为class的原型方法,只是作为了实例的方法,每次render也会产生新的函数

    3. 构造函数方法

      constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
      }
      

      没个实例都可以共享函数体,不需要额外的内存负担,但是函数太多的话绑定起来比较麻烦。

七、webpack打包

webpack可以通过抽离css,拆分js来实现,文件名使用[name].[chunkhash].js

css抽离

使用css-loader压缩css,使用mini-css-extract-plugin把css抽离出来,使用浏览器进行缓存

js拆分

将插件与实际的业务逻辑代码分离,比如react、react-dom、flux、react-intl、axios等一般不会变的分离出来,形成一个或多个文件,这样每次修改代码后只有业务代码文件名的hash值会变,插件的hash值不会变,用户打开页面时只需要重新获取变化的文件,缩短加载时间

八、预加载

preload/prefetch告诉浏览器提前加载资源,在需要执行的地方再执行。

好处:
  • 将加载和执行分开,不阻塞渲染和document的onload事件
  • 提前加载资源,不会出现以来的font隔一段时间才出现,防止屏幕闪烁
preload/prefetch区别:
  • preload: 必需要加载的资源,浏览器一定会加载该资源;将提升资源的优先级;由于资源一定会被加载,所以必须保证资源一定会用到,否则会给页面带来一定负担。
  • Prefetch: 资源可能需要加载,浏览器不一定会加载

当对同一个资源同事使用preload、prefetch会加载两次,带来两倍的网络开销

使用preload加载跨域资源时应加上crossorigin,避免资源不同源无法使用缓存,不带crossorigin时请求头没有origin字段。

九、预解析

当浏览器获取资源的时候,需要先进行dns解析,才能获取到资源。dns-prefetch用预解析dns,当需要获取资源时直接使用解析好的值

<link rel="dns-prefetch" href="xyz.com">
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值