浅谈前端性能优化

88 阅读5分钟

你是否有过以下经历?

  1. 生活中:
  • 页面加载好慢,等待时间太长,退出……
  • 页面交互一次,半天无反应,退出……
  1. 工作中:
  • 性能优化方面了解多吗?
  • 对公司网站,有没有什么优化的想法💡?

什么是web性能?

MDN上对web性能的定义:

Web 性能是客观的衡量标准,是用户对加载时间和运行时的直观体验。Web 性能指页面加载到可交互和可响应所消耗的时间,以及页面在交互时的流畅度——滚动是否顺滑?按钮能否点击?弹窗能否快速打开,动画是否平滑?Web 性能既包括客观的度量如加载时间,每秒帧数和到页面可交互的时间;也包括用户的对页面内容加载时间的主观感觉。

简单理解: 网站的加载速度快不快,运行效率高不高,用户体验好不好~

为什么要关注web性能?

页面的快速响应有以下几点:

  • 提升用户的留存
  • 提升转化率
  • 良好的体验,减少用户投诉,加速网站的传播
  • 等等……

web性能的指标是什么?

为了能衡量用户视觉体验,在以用户为中心的目标,性能指标不断演进。其中,RAIL是由Google Chrome 团队于 2015 年提出的性能模型, 用于提升浏览器内的用户体验和性能。

image.png

响应(Response):

  • 目标:100ms 内完成由用户输入启动的转换,让用户感觉交互是即时的。

动画(Animation):

  • 目标:10ms产生一帧。
  • 准则: 尽可能利用 100ms响应预先计算昂贵的工作,以便最大限度地提高达到 60 fps 的机会。

fps(Frames Per Second): 每秒绘制帧数

浏览器空闲时间(Idle):

  • 目标: 最大化利用空闲时间以增加页面在 50ms内响应用户输入的几率。
  • 准则: 利用空闲时间完成延期工作。 例如,对于初始页面加载,加载尽可能少的数据,然后使用空闲时间加载其余的数据。

加载(Load):

  • 目标: 根据用户的设备和网络能力优化相关的快速加载性能。
  • 准则: 目前对于网速快的电脑设备,应该在小于 1s-2s 的时间内加载完成网站,并可以进行用户交互。对于首次加载,在使用速度较慢 3G 连接的中端移动设备上,理想的目标是在 5s或更短的时间内实现可交互。

如何检测web性能

image.png

  • FCP: 首次内容绘制浏览器首次绘制来自 DOM 的内容的时间,内容必须是文本图片(包含背景图)、非白色的 canvas 或 SVG,也包括带有正在加载中的 Web 字体的文本
  • TTI: 表示网页第一次 完全达到可交互状态 的时间点,浏览器已经可以持续性的响应用户的输入
  • TBT: 总阻塞时间,度量了 FCPTTI 之间的总时间,在该时间范围内,主线程被阻塞足够长的时间(任务在主线程上运行超过50ms)以防止输入响应。导致用户感觉到延迟,页面缓慢。
  • CLS: 累计布局偏移,是一种保证页面的视觉稳定性从而提升用户体验的指标方案。
  • SI: 速度指数,表示页面可视区域中内容的填充速度的指标。

报告提出的一些建议可行性方向:

image.png

  • 浏览器开发工具

    • 浏览器任务管理器 (点击浏览器右侧3个点 - > 更多工具 - > 任务管理器)

    • network网络分析 (大小,时间 ,时间线->ttfp 等待时间 ,网络加载状态,禁用缓存)

    • perfomance image.png 第一个是记录你的操作的一些性能报告

      第二个是发出请求到页面加载的性能报告

    • fps显示每秒帧数计量器 (在浏览器中使用ctrl+shift+p调起面板可搜索)

  • Performance API: HTML5新增的API 早期你肯定也用过console.time()console.timeEnd()来跟踪某一操作的占用时长。这种操作相对来说麻烦且不友好。W3C后面推出了Performance这个API。

直接在控制台输入 window.perforamce.timing

image.png 具体字段解释如下:

const timingInfo = window.performance.timing;
// DNS解析,DNS查询耗时
timingInfo.domainLookupEnd - timingInfo.domainLookupStart;
// TCP连接耗时
timingInfo.connectEnd - timingInfo.connectStart;
// 获得首字节耗费时间,也叫TTFB
timingInfo.responseStart - timingInfo.navigationStart;
// domReady时间(与DomContentLoad事件对应)
timingInfo.domContentLoadedEventStart - timingInfo.navigationStart;
// DOM资源下载
timingInfo.responseEnd - timingInfo.responseStart;
// 准备新页面时间耗时
timingInfo.fetchStart - timingInfo.navigationStart;
// 重定向耗时
timingInfo.redirectEnd - timingInfo.redirectStart;
// Appcache 耗时
timingInfo.domainLookupStart - timingInfo.fetchStart;
// unload 前文档耗时
timingInfo.unloadEventEnd - timingInfo.unloadEventStart;
// request请求耗时
timingInfo.responseEnd - timingInfo.requestStart;
// 请求完毕至DOM加载
timingInfo.domInteractive - timingInfo.responseEnd;
// 解释dom树耗时
timingInfo.domComplete - timingInfo.domInteractive;
// 从开始至load总耗时
timingInfo.loadEventEnd - timingInfo.navigationStart;
// 白屏时间
timingInfo.responseStart - timingInfo.fetchStart;
// 首屏时间
timingInfo.domComplete - timingInfo.fetchStart;

  • performance monitor

console -> more tools -> performance monitor

image.png

性能优化部分实践

  • css资源的处理

    • 使用CSS Minifiers

    我们可以在webpack中使用 CSSNano或 csso来对我们的CSS代码来进行压缩。

    //postcss.config.js
     module.exports = {
         plugins: [
             require('cssnano')({
                 preset: 'default',
             }),
         ],
     };
    

    CSSNano 提供了多方面的体积优化能力,例如移除不必要的厂商前缀、对属性进行排序以获得更高的 Gzip 压缩比等

  • JS文件

    • 使用 async 或 defer 属性

    推荐使用 async 或 defer 属性标记非关键 JS 文件。

    由于 async 或 defer 的执行时机不一致: image.png 通常我们使用 defer 标记需要按照一定顺序执行的脚本,例如业务代码;使用 async 标记一些没有任何依赖的脚本,如埋点、性能统计脚本等.

    • 去除重复、无用的js文件

    可以通过webpack-bundle-analyzer获取当前项目的分析图。

    • 如何降低包的大小

    1、使用路由懒加载,分包

    2、第三方库按需加载

    3、使用compressionWebpackPlugin使用gizp压缩

    4、使用组件的异步加载

    5、打包的时候取消.map文件

    6、使用uglifyJS或者terserWebpackPlugin去压缩js代码

  • 代码层面

    • 防抖节流
    • 利用requestAnimationFrame 代替 setTimeOut 实现动画
    • 定时器、事件监听等记得卸载。