前端性能优化分两部分

1、加载性能优化

2、渲染性能优化

一、加载性能优化

本质:

  • 1、减少请求次数;
  • 2、减少请求资源的大小;
  • 3、网络优化;
1、减少请求次数
为什么减少请求次数?

浏览器能够并行发出请求,但是每次并行发出请求的个数是有限制的,以chrome为例:

  • 同一域名下,同一GET请求的并发数是1,也就是说上一个请求结束,才会执行下一个请求,否则置入队列等待发送;
  • 同一域名下,不同GET/POST请求的并发数量是6。当发送的请求数量达到6个,并且都没有得到响应时,后面的请求会置入队列等待发送。

所以资源请求数过多肯定比请求数少更耗时,直接影响网页的加载速度;

减少请求次数方式
  • 1)图片资源

    • CSS雪碧图技术

      把一些常用、重复使用的小图合并成一张大图,使用的时候通过背景图片定位(background-position),定位到具体的某一张小图上;

      1、UI给图;

      2、webpack插件:webpack-spritesmith

    • 图片懒加载

      视区外图片先不加载,当进入视区或者进入视区之前的某个位置加载;

      1、css的loading属性;

      2、getBoundingClientRect方法,获取dom元素的top、left、bottom、right、height、width信息,对比视区大小,进行图片加载(需要结合节流);

      3、IntersectionOberser方法,能够监听元素是否到达当前视口的事件;

    • 字体图标

      一个图标字体比一系列图像要小,一旦图标字体加载了,图标就会马上渲染出来,不需要下载一个图像,可以减少HTTP请求。

    • base64编码

      图片的base64编码就是可以将一张图片数据编码成一串字符串,使用该字符串代替图像地址url;

      (均衡css体积增大和http请求减少之间的收益)

  • 2)合理利用缓存

    • 浏览器缓存(资源)

      强缓存

      协商缓存

    • DNS缓存(DNS查找时间)

    • 分包加载 (Bundle Spliting)

      • 避免一行代码修改导致整个 bundle 的缓存失效
  • 3)合并CSS和JS文件

    将CSS和JavaScript文件合并为单独的文件。合并CSS和JavaScript文件是减少HTTP请求数量和提高网站加载速度的有效方法;

2、减少资源大小

相同网络环境下,更小体积意味着传输速度更快;

减少资源大小方式
  • 1)资源压缩

    • js、css、html资源压缩

      • gzip压缩:nginx配置中可以开启,资源传输体积压缩变小,相应会增加服务器压缩和浏览器资源解压的压力;对于图片资源压缩效率不明显;

      • Terser 等工具是 Javascript 资源压缩混淆的神器。对代码层进行处理,比如:

        • 1、长变量名替换短变量;

        • 2、删除空格换行符;

        • 3、预计算能力;

        • 4、移除无法被执行的代码;

        • 5、移除无用的变量及函数

    • 图片资源压缩

      • 图片压缩工具:tinyPng等

      • 图片格式:,webp 普遍比 jpeg/png 更小,而 avif 又比 webp 小一个级别

        如何鉴别浏览器是否支持webp?

        • 通过canvas来判断(这个比较常用),创建一个canvas元素,然后把它转成image/webp格式的data_url,如果这个data_url里面包含webp,则代表当前浏览器支持webp格式, 反之则不支持:document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp')
        • 在服务端根据请求header信息判断浏览器是否支持webp:在图片请求发出的时候,Request Headers 里有 Accept,服务端可以根据Accept 里面是否有 image/webp 进行判断。
        • 通过加载一张 webp 图片进行判断:先加载一个WebP图片,如果能获取到图片的宽度和高度,就说明是支持WebP的;
  • 2)Tree Shaking技术

    Tree Shaking: 无用导出将在生产环境进行删除,到达减少资源体积的效果;

3、网络优化
  • 1)CND:就近原则

  • 2)Http2.0

    1. 多路复用,在浏览器可并行发送 N 条请求。
    2. 首部压缩,更小的负载体积。
    3. 请求优先级,更快的关键请求
其他
  • 路由懒加载
  • 第三方组件按需加载
  • ···

二、渲染性能优化

浏览器渲染过程
  1. 解析HTML生成DOM树。
  2. 解析CSS生成CSSOM规则树。
  3. 解析JS,操作 DOM 树和 CSSOM 规则树。
  4. 将DOM树与CSSOM规则树合并在一起生成渲染树。
  5. 遍历渲染树开始布局,计算每个节点的位置大小信息。
  6. 浏览器将所有图层的数据发送给GPU,GPU将图层合成并显示在屏幕上。

img

重排

当改变 DOM 元素位置或大小时,会导致浏览器重新生成渲染树,这个过程叫重排。

重绘

当重新生成渲染树后,就要将渲染树每个节点绘制到屏幕,这个过程叫重绘。

不是所有的动作都会导致重排,例如改变字体颜色,只会导致重绘。

重排和重绘这两个操作代价非常大,因为 JavaScript 引擎线程与 GUI 渲染线程是互斥,它们同时只能一个在工作,因此重排和重绘会阻塞主线程。

渲染性能优化方式
  • 1)资源加载优先级控制

    • preload/prefetch

      preload/prefetch 可控制 HTTP 请求优先级,从而达到关键请求更快响应的目的;

      • preload 加载当前路由必需资源,优先级高,一般对于 Bundle资源使用preload;

      • refetch 优先级低,在浏览器 idle 状态时加载资源,一般用以加载非首页资源;

      dns-prefetch,可对主机地址的 DNS 进行预解析。

    • js和css的引入位置/script类型设置

      • css引入放在head便签尾部,script脚本防砸body标签尾部;
      • 脚本与DOM/其它脚本的依赖关系很强:对<script>设置defer
      • 脚本与DOM/其它脚本的依赖关系不强:对<script>设置async
  • 2)减少重排重绘

    • 减少页面DOM操作;
    • 对 DOM 元素执行一系列操作,可以将 DOM 元素脱离文档流,修改完成后,再将它带回文档。例如:隐藏元素(display:none)、文档碎片(DocumentFragement)等(虚拟dom);
    • 用 JavaScript 修改样式时,最好不要直接修改单个样式属性,而是替换 class 来改变样式;
    • 合理使用防抖和节流;
  • 3)利用缓存

    • 页面缓存(keep-alive),接口缓存(减少数据更新导致的页面刷新)
  • 4)Web Worker

    • 用于那些处理纯数据,或者与浏览器 UI 无关的长时间运行脚本;

三、页面加载指标

API指标

window.performence.timing

  • fetchStart: 浏览器准备好使用 HTTP 请求抓取文档的时间,这发生在检查本地缓存之前。
  • domainLookupStart/domainLookupEnd: DNS 域名查询开始/结束的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等;
  • connectStart: HTTP(TCP)开始/重新 建立连接的时间,如果是持久连接,则与 fetchStart 值相等。
  • requestStart: HTTP 请求读取真实文档开始的时间(完成建立连接),包括从本地读取缓存。
  • responseStart: HTTP 开始接收响应的时间(获取到第一个字节),包括从本地读取缓存。
  • responseEnd: HTTP 响应全部接收完成的时间(获取到最后一个字节),包括从本地读取缓存。
  • domLoading: 开始解析渲染 DOM 树的时间,此时 Document.readyState 变为 loading,并将抛出 readystatechange 相关事件。
  • domInteractive: 完成解析 DOM 树的时间,Document.readyState 变为 interactive,并将抛出 readystatechange 相关事件,注意只是 DOM 树解析完成,这时候并没有开始加载网页内的资源。
  • domContentLoadedEventStart: DOM 解析完成后,网页内资源加载开始的时间,在 DOMContentLoaded 事件抛出前发生。
  • domContentLoadedEventEnd: DOM 解析完成后,网页内资源加载完成的时间(如 JS 脚本加载执行完毕)。
  • domComplete: DOM 树解析完成,且资源也准备就绪的时间,Document.readyState 变为 complete,并将抛出 readystatechange 相关事件。
  • loadEventStart: load 事件发送给文档,也即 load 回调函数开始执行的时间。
  • loadEventEnd: load 事件的回调函数执行完毕的时间。
页面指标

白屏时间

指浏览器发起请求到开始显示第一个页面元素的时间。现代浏览器不会等待CSS树(所有CSS文件下载和解析完成)和DOM树(整个body标签解析完成)构建完成才开始绘制,而是马上开始显示中间结果。所以经常在低网速的环境中,观察到页面由上至下缓慢显示完,或者先显示文本内容后再重绘成带有格式的页面内容。

window.performence.timing.domLoading - window.performence.timing.fetchStart

首屏时间

首屏时间(FirstScreen Time),是指用户看到第一屏,即整个网页顶部大小为当前窗口的区域,显示完整的时间。常用的方法有,页面标签标记法、图像相似度比较法和首屏高度内图片加载法。

可交互时间

用户可以进行正常的点击、输入等操作,默认可以统计DOMContentLoaded事件发生的时间。

window.performence.timing.domContentLoadedEventEnd - window.performence.timing.fetchStart

整页时间

整页时间(Page Load Time),页面所有资源都加载完成并呈现出来所花的时间,这个就是load事件发生的时间。

window.performence.timing.loadEventEnd - window.performence.timing.connectStart

DevTools指标

在使用Google Chrome开发者工具的是,使用Network测试网络性能时候,下面有三个时间。

  • Finish: 1.31s -表示整个页面加载时间为640ms,包括load事件发生后还有一些异步资源也加载完成。
  • DOMContentLoaded: 329ms -发生在页面DOMContentLoaded事件的启动时间点,对应上图蓝色竖线。
  • Load: 1.25s -表示页面load事件的启动时间点,对应上图红色竖线。
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐