前端相关 性能优化

前端性能优化主要分为几个维度:

1. 网络请求层面的优化

  • 减少 http 的请求次数和大小
    • 资源的合并压缩【例如:CSS合并为一个、JS合并为一个、雪碧图 --> webpack】
      • CSS 代码不多的情况下采用内嵌式
    • 图片音视频的懒加载【首次渲染页面,减少 HTTP 请求,以此来优化白屏等待时间,当页面渲染完,再去请求真正的图片】
    • 音视频采用流信息播放【原因:减少 HTTP 请求 & 加快样式渲染】
    • 尽量使用字体图标或者SVG图标,需要使用图片时,图片格式尽可能使用Webp(保证质量的情况下把体积压缩到最小),体积比较小的图片(10K以下的样子)转化成 Webp 反而体积变大了,小图就可以使用Base64。
    • 图片使用BASE64【正常方式加载图片,需要经历:请求、编码、渲染三个步骤,而每个步骤都需要一些时间,而BASE64是直接给图片设置对应的编码,浏览器只需要渲染即可。问题:BASE64码太长了,不方便开发和维护,也增加了页面请求的时间,所以真实项目中,BASE64我们一般会基于Webpack编译生成,而且不要过度使用】
    • .....
  • DNS的预解析
  • 使用 Webwoker 和 scoket.io 实现数据实时通信,避免长轮询
  • 开启 HTTP 的 Connection:Keep-Alive 长连接
  • 采用缓存机制:强缓存、协商缓存、数据缓存 浏览器 的 协商缓存 与 强缓存
  • 使用 HTTP2.0 来处理【多路复用 & 主动推送 & 减少头信息的传输 & 二进制格式传输】
  • 减少对于 Cookie 的使用(最主要的是减少本地 Cookie 存储内容的大小),【原因:每一次向服务器请求,都会把 cookie 带上】
  • 基于 ajax/fetch 获取的数据,对于不经常更新的做缓存【本地存储】
  • ....

2. 代码渲染层面的优化

  • CSS 资源的导入放在页面头部(让页面元素带着样式渲染)
  • JS 资源的导入放在页面的底部(JS一般都是用来操作DOM元素的,需要等到元素加载完再操作)【可以设置 defer/async】,这两个属性都使得 script 不会阻塞 DOM 的渲染。详情点击script 标签
  • 避免使用 @import,防止阻塞 GUI(用户界面)的渲染。比如加载 CSS 最好用 <link>,因为 @import 是同步操作,而 link 是异步操作。
  • 减少DOM的层级嵌套
  • 页面中出现音视频标签,我们不让页面加载的时候就去加载这些资源(要不然页面加载速度会变慢)(方案:只需要设置 preload='none' 即可),等待页面加载完成,音视频播放的时候我们在去加载音视频资源
  • 基于骨架层【SSR或者前端骨架屏】,减少首屏加载的时间【防止白屏效果】
  • 避免使用 table 布局
  • ...

2.1 减少DOM的重排和重绘

浏览器渲染一个页面的时候是按照“先创建DOM树->再加载CSS->生成渲染树 RENDER TREE->把渲染树交给浏览器(GPU)进行绘制”,如果后期我们修改了元素的样式(但是没有改变大小和位置),浏览器会把当前元素重新生成渲染树,然后重新渲染,这个机制是重绘,但是一旦元素的位置或者大小等发生改变,浏览器就要从DOM树重新计算渲染,这个机制是回流(重排),不论是重排还是重绘都非常的消耗性能,尽量减少操作 DOM 引发的回流和重绘问题,常用的解决方案:

  • 使用 Vue/React 框架,避免直接操作 DOM【本质:框架本身把DOM操作进行了封装,在内部实现了对DOM的优化处理】
  • 分离读写【尽量把统一修改样式都放到一起执行,因为新版浏览器都有一个自己检测的机制,如果发现下面紧挨着的操作也是修改元素的样式,会把所有修改的事先存起来,直到遇到非修改样式的操作,会把之前存储的统一执行,引发一次回流和重绘】
  • 文档碎片(或者字符串拼接)实现 DOM 的批量创建
  • 使用一些高性能的样式属性去修改样式:transform、opacity....【修改元素的transform会把元素单独脱离出一个文档流,不会引发原始文档流的重排】
  • 改变样式的元素最好有一个独立的文档流【可以使用 position 】
  • ....

2.2 CSS相关优化

  • 避免渲染器层级过深(前缀不要太长)【比如:.div1 .container #box1 .link {...}可以简写成#box1 .link {...}
  • 在使用CSS选择器的时候尽可能减少对标签选择器的使用。【比如:.container .link a {...}CSS选择器解析规则是从右向左解析,先找到所有的 a,再筛选是在 .link 样式类中的,再次筛选是在 .container 样式类中的... 先找到的是所有的 a,操作起来是消耗性能的。】
  • 避免使用 CSS 表达式【calc、expression、...】
    #myDiv {
      position: absolute;
      width: calc(100vh - 100px);
      left: expression(document.body.offsetWidth - 110 + "px");
      /* 隔一个小时切换一次背景颜色 */
      background-color: expression((new Date()).getHours()%2 ? "#FFFFFF": "#000000" );
    }
    
  • 减少对 filter(滤镜属性) 的使用【这个属性消耗性能较大一些】
  • 能基于 CSS3 实现动画的,绝对不用 JS【JS最好基于requestAnimationFrame实现动画】,CSS 处理动画等功能的性能优于JS,而且 CSS 中的 transform 变形还开起了硬件加速
  • ....

2.3 JS相关优化(内存优化、复杂度优化、性能优化)

  • 堆栈内存的有效管理【含:闭包的合理使用 & 作用域链优化...】
  • 尽可能的手动释放没用的内存“内存优化”,比如定时器。
  • 避免使用:with、eval等【性能消耗较大】
  • 避免循环嵌套和死循环
  • 减少对递归的使用,避免死递归
  • 利用事件轮询的冒泡机制(事件委托),减少对元素的循环绑定【堆栈内存都有优化 & 给动态绑定的元素实现事件绑定】。
  • 尽量使用设计模式来管理我们的代码(单例、构造、Promise、发布订阅),方便后期的升级和维护。
  • 设计数据结构的时候尽量扁平化,减少循环获取数据时候的复杂度。
  • 函数的防抖和节流,降低触发的频率
  • 尽可能实现JS的封装(低耦合高内聚),增加复用率,减少页面中的冗余代码。
  • 使用正则表达式虽然可以很方便的处理字符串,但是复杂的正则表达式也会带来性能上的损耗。
  • 循环中各种方式的性能对比(好->坏):for/while、内置方法[例如:forEach]、for of、 for in
  • 基于IntersectionObserver代替传统的window.onscroll
  • ....

2.4 基于骨架层【SSR或者前端骨架屏】,减少首屏加载的时间【防止白屏效果】

  • 服务器渲染{SSR} 【vue:nuxt.js react:next.js】
    • 服务器渲染有利于SEO优化,而客户端渲染是做不了的
    • 在"服务器并发压力较强"的情况下,服务器渲染是可以更快实现页面渲染的
    • 弊端: 导致服务器压力过大,前后端没有完全分离...
    • 服务器只需要完成首屏信息的渲染即可,其余屏幕还是交给客户端完成
  • 纯前端骨架屏方案【Loading效果】

2.5 SEO 优化

搜索引擎优化,利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名。

  • HTML5 的语义化标签
  • 避免404
  • 服务器渲染【有响应的缺点】

2.6 CDN

做 CDN 加速,使用 CDN 【服务器分布式】,比较烧钱。

  • 增加带宽
  • 增加分发节点

3. 打包编译层面的优化 webpack 优化

4. 额外方案

  • 前后端通信,尤其是实时通信{IM即时通信系统,例如:QQ和微信...},可以使用scoket.io等最新的通信技术

5. react 项目中的优化

posted @ 2019-09-30 14:41  真的想不出来  阅读(483)  评论(0编辑  收藏  举报