前端性能优化

首先明确从输入url到页面渲染完成中间发生了什么:
DNS解析(获取ip)–>建立TCP链接(三次握手)–>http请求–>返回响应资源数据—>客户端解析渲染

从每个阶段分析,逐步优化

DNS解析

DNS 实现域名到IP的映射。通过域名访问站点,每次请求都要做DNS解析。目前每次DNS解析,通常在200ms以下。

  1. 减少DNS查找,合理分配资源在cdn(域名)上
  2. DNS预获取,perfetch提前解析可能即将访问的资源

    浏览器会自动对a标签href预获取,所以不需手动设置,但在https中需设置meta强制开启才起作用。这个限制的原因是防止窃听者根据DNS Prefetching推断出显示在HTTPS页面中超链接的主机名。

1
<meta http-equiv="x-dns-prefetch-control" content="on">

关于预获取预加载

TCP优化

主要目的是减少TCP链接次数,即减少http请求

  1. 使用长连接
    • http头中Connection:keep-alive
  2. 使用http2.0
    • 复用TCP通道
    • 压缩报头
    • 采用二进制格式而非文本格式
    • 支持cache push(server push)

http优化

  1. 利用cdn内容分发网络
    • 基于端口跟线程切换开销,浏览器不可能无限的并发请求。chrome的并发为6(同一域名中),超过限制数目的请求就会被阻塞
    • 将静态资源(js,css,image…)缓存在离用户近的运营商网络cdn节点,提高响应速度,降低带宽、负载消耗
  2. 浏览器缓存
    • 强缓存
    • 协商缓存
  3. 合并http请求

响应资源优化

  1. 资源压缩合并
    • html,css压缩
    • js压缩混乱
    • 文件合并
  2. css背景精灵图
  3. 图片优化
  4. 使用字体图标

渲染优化

浏览器渲染原理与流程

  1. 控制加载顺序
  2. 异步/延迟加载
    • async(加载不阻塞,执行阻塞) 非核心代码异步加载,加载完就执行,不保证顺序
    • defer(加载异步不阻塞,执行推迟) 解析完才执行,保证顺序
  3. 服务端渲染
    有利于SEO,服务端将整个html渲染好返回给客户端
    • SEO :可以有“现成的内容”拿给搜索引擎看
    • ⾸屏加载速度:服务端渲染模式下,服务器给到客户端的已经是⼀个服务端处理好的可以拿来呈现给⽤户的⽹⻚
    • 缺点: ⾮常吃硬件资源
  4. 减少重排(回流)重绘
    • 重排: 改变 DOM 元素位置或大小时,会导致浏览器重新生成渲染树,这个过程叫重排。
    • 重绘: 渲染树每个节点绘制到屏幕,这个过程叫重绘(重绘不一定重排,如变字体颜色)
    • 用 JavaScript 修改样式时,最好不要直接写样式,而是替换 class 来改变样式
    • 如果要对 DOM 元素执行一系列操作,可以将 DOM 元素脱离文档流,修改完成后,再将它带回文档。推荐使用隐藏元素(display:none)或文档碎片(DocumentFragement)
  5. 图片懒加载
    • 将img标签src指向一张小图片,然后定义data-src自定义属性指向真实的图片,当载入页面时,先把可视区域内的img标签的data-src属性值赋给src,然后监听滚动事件,把用户即将看到的图片加载
    • src不能为空,否则会多次发起请求
  6. 节流/防抖
    • 节流: 规定时间内只执行一次函数,滚动事件中,规定事件内不触发逻辑方法
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      function throttle(fn, delay) {
      let prevTime = Date.now();
      return function() {
      let curTime = Date.now();
      if (curTime - prevTime > delay) {
      fn.apply(thisarguments);
      prevTime = curTime;
      }
      };
      }
      // 定时器版
      function throttle(fn, delay = 1000) {
      let timer = null
      return function (args) {
      let that = this
      let _args = args
      if(!timer) {
      timer = setTimeout(function() { // 定时器回调函数中this指向window,所以下边需要固定this指向(或者改为箭头函数)
      fn.call(that, _args)
      timer = null
      }, delay)
      }
      }
      }

      // 使用
      var throtteScroll = throttle(function() {
      console.log('throtte');
      }, 1000);
      window.onscroll = throtteScroll;
    • 防抖: 搜索框实时搜索,每次定时器清除重计,保证输入完规定时间后请求一次
      1
      2
      3
      4
      5
      6
      7
      8
      9

      function debounce(fn, delay = 1000) {
      return function(args) {
      clearTimeout(fn.timer)
      fn.timer = setTimeout(() => {
      fn.call(this, args)
      }, delay)
      }
      }

VUE相关优化

  • 不必要的文件不打包到生产(mock,console等)
  • 提取css为单独文件
  • 利用Object.freeze()提升性能
    • 一个普通的 JS 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用Object.defineProperty 把这些属性全部转为 getter/setter,但 Vue 在遇到像 Object.freeze() 这样被设置为不可配置之后的对象属性时,不会为对象加上 setter getter 等数据劫持的方法。
  • 路由组件懒加载
  • ui库按需加载

编码方面优化

  • if,switch的选择
  • v-if,v-show
  • 组件化
  • 封装
  • 各种循环的性能比较
  • 尽量避免闭包

参考:

关于前端性能的优化(总结)
前端性能优化小结(面试干货)
前端性能优化 24 条建议