前端性能笔记

390 阅读4分钟

整理自拉勾教育《前端高手进阶》

kaiwu.lagou.com/course/cour…

从性能指标,统计方式,优化思路三个层面讲解了前端性能优化的过程

性能指标

首屏绘制( FP )

首屏绘制由 W3C 标准 Paint Timing 中提出。

www.w3.org/TR/paint-ti…

首屏绘制时间是指从开始加载到浏览器首次绘制像素到屏幕上的时间,也就是页面在屏幕上首次发生视觉变化的时间。注意首屏绘制不包括默认的背景绘制,但包括非默认的背景绘制。由于首次绘制之前网页呈现默认背景白色,所以也俗称“白屏时间”。

        performance.getEntriesByType('paint')[1]
	/*
          duration: 0
          entryType: "paint"
          name: "first-paint"
          startTime: 11383.625000016764
     	*/

首屏内容绘制( FPC )

首屏内容绘制由 W3C 标准 Paint Timing 中提出。浏览器首次绘制来自 DOM 的内容时间,这个内容可以是文字、图片(也包括背景图片)、非空白的 canvas 和 svg。

        performance.getEntriesByType('paint')[0]
   	/*
           duration: 0
           entryType: "paint"
           name: "first-contentful-paint"
           startTime: 11383.625000016764
   	*/       

FCP 有时候会和 FP 时间相同,也可能晚于 FP。这也很好理解,FP 只需要满足“开始绘制”这一个条件就可以了,而 FCP 还要满足第二个条件,那就是“绘制的像素有内容”。

可交互时间(Time to Interactive,TTI)

可交互时间由 Web 孵化器社区组(WICG)提出 wicg.io/

定义:指网页在视觉上都已渲染出了,浏览器可以响应用户的操作了。 实际测量起来要考虑两个条件: 第一个条件是主线程的长任务(长任务是指耗时超过 50 ms)执行完成后 第二个条件是随后网络静默时间达到 5 秒,这里的静默时间是指请求数不超过 2 个, 排除失败的资源请求和未使用 GET 方法进行的网络请求。

TTI 测量可以使用 Google 提供的模块 tti-polyfill www.npmjs.com/package/tti…

import ttiPolyfill from 'tti-polyfill'; 
ttiPolyfill.getFirstConsistentlyInteractive(opts).then((tti) => { 
  ... 
});

总阻塞时间(Total Blocking Time,TBT)

总阻塞时间由 W3C 标准 Long Tasks API 1 提出,是指阻塞用户响应(比如键盘输入、鼠标点击)的所有时间。指标值是将 FCP 之后一直到 TTI 这段时间内的阻塞部分时间总和,阻塞部分是指长任务执行时间减去 50 毫秒

var observer = new PerformanceObserver(function (list) { 

  var perfEntries = list.getEntries(); 

  for (var i = 0; i < perfEntries.length; i++) { 

    console.log(perfEntries[i].toJSON()) 

  /* 

  { 

    attribution: [TaskAttributionTiming], 

    duration: 6047.770000004675, 

    entryType: "longtask", 

    name: "self", 

    startTime: 22.444999995059334 

  } 

  */ 

  } 

}); 

observer.observe({ 

  entryTypes: ["longtask"] 

});

最大内容绘制(Largest Contentful Paint,LCP)

最大内容绘画指的是视口内可见的最大图像或文本块的绘制时间。测量这个指标的值和 TBT 相似,不同的是将实体类型改为“largest-contentful-paint”。

var observer = new PerformanceObserver(function (list) { 

  var perfEntries = list.getEntries(); 

  for (var i = 0; i < perfEntries.length; i++) { 

    console.log(perfEntries[i].toJSON()) 

    /* 

    { 

      duration: 0, 

      element: img, 

      entryType: "largest-contentful-paint", 

      id: "", 

      loadTime: 274.864, 

      name: "", 

      renderTime: 0, 

      size: 2502, 

      startTime: 274.864, 

           url: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png" 

      } 

    */ 

  } 

}); 

observer.observe({entryTypes: ['largest-contentful-paint']});

统计方式

平均值统计

不精确,用户之间实际差距大

百分位数统计

适合用于性能统计

优化思路

前端性能优化一般可以从两个方向入手:加载性能优化和渲染性能优化。

加载性能的优化

减法:

采用 gzip 压缩,典型的减少资源的传输体积;

使用缓存,强制缓存可以减少浏览器请求次数,而协商缓存可以减少传输体积;

使用雪碧图,减少浏览器请求次数。

除法:

HTTP2 多路复用,把多个请求拆分成二进制帧,并发传输;

懒加载,将 Web 应用拆分成不同的模块或文件,按需加载;

把 script 标签放到 body 底部,通过调整顺序来控制渲染时间。

渲染性能优化

减法:

避免重排与重绘,减少渲染引擎的绘制;

防抖操作,减少函数调用或请求次数;

减少 DOM 操作,减少渲染引擎和脚本引擎的切换,同时也减少渲染引擎绘制。

除法:

骨架屏,将页面内容进行拆分,调整不同部分的显示顺序;

使用 Web Worker,将一些长任务拆分出来,放到 Web Worker 中执行;

React Fiber,将同步视图的任务进行拆分,可调换顺序,可暂停。

今天看了这个分类之后,终于明白为什么之前面试的时候回答这个问题,面试官会皱眉头了,因为都是背的,太没有条理性了!