前端性能优化一:性能指标

若是咱们想要提升咱们的前端性能,那么首先你得先只知道怎么测量你的前端性能。可是哪些前端的性能指标咱们应该关注呢? 在Web1.0时代当咱们讨论到前端性能指标用的最多的就是page load time。到了单页应用程序愈来愈多的时代,单一的page load time指标已经没法彻底衡量前端性能了,由于一个单页应用程序page load time可能只触发了一次,可是用户会跟程序有不少的交互,每个交互或者动做都须要有指标来衡量他的性能。javascript

接下来就介绍几个比较重要的前端性能指标:前端

  • first paint (FP):这个指标标志着浏览器渲染第一个像素点的时间
  • first contentful paint (FCP):和FP标志着任意一个像素点被渲染的时间不一样,FCP标志着浏览器渲染第一个内容元素的时间,这些内容元素能够是text,image,SVG,canvas.

这两个指标对用户来讲都是很重要的,这两个指标能够认为咱们程序正在告诉咱们的用户:咱们正在正确工做。java

  • First meaningful paint (FMP):这个指标标志着首屏最重要的一块区域的渲染,一般是用户最关注的区域。好比视频网站的视频播放区域,搜索网站的第一个搜索结果区域,又或者是购物网站的照片首图。一般来讲浏览器很难清楚的了解哪一块是对于网站首屏来讲是最关键的,因此开发者本身来告诉浏览器是哪一块是关键区域是颇有必要的。

这也是很是关键的一个指标,一般若是用户可以快速的看到最重要的一块区域被渲染完成,即便其余的区域都尚未被渲染用户可能也不会注意到。git

  • long task:咱们都知道浏览器是单线程的在响应用户的操做时经过在任务队列里面增长任务,而后一个个的执行的.这意味着若是咱们有一个长任务须要使用较长的时间,那么队列中的其余任务就只能等待,响应用户的操做就会变慢,或者动画就会变卡顿。
  • Time to interactive (TTI):这个指标表示浏览器已经渲染完了咱们首屏须要显示的内容而且已经准备好接受用户的交互信息了,也标志着程序是否可用。程序暂时没法响应用户的交互有下面几个缘由:
    • 须要执行的javascript尚未执行完成。
    • 有长任务阻绝着主线程.没法给用户响应。
指标 介绍
first paint (FP)/first contentful paint (FCP) 程序是否正确的开始渲染
First meaningful paint (FMP) 用户最关注的的首屏内容显示
Time to interactive (TTI) 程序是否可用
long task 程序使用的体验(是否响应延迟,动画卡顿)

还有一些其余的指标好比 First Input Delay(首次接受用户响应的延迟时间) First CPU Idle(第一次CPU闲置的时间):这些指标都和上面的指标有着直接的关系。github

用户体验

知道了这些指标,咱们要把这些指标控制在什么样的时间才能给用户带来比较好的用户的体验呢,下面有这样一张表web

时间 介绍
0到16ms 用户但愿看的动画可以流畅,动画卡顿会带来很是差的用户体验,在浏览器上每秒钟渲染60帧动画就可以保持流畅,这大约就是16ms渲染一帧,这16ms包括了浏览器要渲染新的元素到页面上须要的时间,也就是说程序有大约10ms的时间能够进行操做。
0到100ms 在这个时间内响应用户的交互,用户会以为响应是很是及时的
100到300ms 用户会感受到有一些延迟
300到1000ms 当执行一些页面加载或者页面跳转的时候,在这个时间内是一个正常的加载跳转时间
1000ms或以上 超过1000ms(1秒),用户会对以前的操做渐渐失去耐心和注意力
10000ms或以上 当你的响应超过10秒,用户会感到烦躁,而后终止以前操做

上面的延迟时间取决于你使用什么样的网络和设备,好比你使用的电脑和wifi网络,用户在1000ms是一个比较现实的目标。可是当你设备是手机网络只有3G的时候在5000ms内加载才是更现实的目标。canvas

响应时间:处理响应用户的操做在50ms之内

在大多数的时间里,用户在使用程序时大多数的时间都在等待网站响应他们的操做好比点击一个按钮,在文本框中输入内容,而不是等待网站加载。那么网站比较理想的响应用户时间是在100ms之内。浏览器

100ms?不是50ms吗?

咱们的目标是在100ms之内响应用户的操做,那为何处理用户的响应时间只有50ms?由于在咱们接受到用户的输入时,可能会有别的任务正在执行.好比咱们接受到用户在文本框中输入了一个A,这个时候浏览器正在执行别的任务,浏览器会把这个操做先加入到任务队列里,等浏览器执行完以前的任务才会去处理用户的响应。那么保守的估计为了让用户在100ms之内得到响应,咱们的处理用户响应的执行时间就是50ms。 性能优化

响应时间

动画:生产每一帧动画的时间在10ms左右

理论上来讲只要没16ms渲染一帧,动画就会看起来是流畅的,可是浏览器大约须要6ms的时间来将每一帧渲染到画面上.所以产生每一帧动画的时间留给程序的大约就10ms左右。服务器

主线程闲置时间越多越好

主线程可以有尽量多的闲置时间,那么当产生用户交互时就能够立马给用户响应。当主线程闲置时,浏览器会有不少的内部程序须要执行,好比闲置GC等。

主要内容渲染完成且程序可交互时间在5秒以内

当页面加载缓慢,用户会失去耐心。网站的加载和响应速度直接影响用户的体验。

如何测试这些指标

使用测试工具或者网站

在真实的用户环境得到这些指标

在介绍如何在用户真实环境中或者这些指标以前先介绍一些API

得到FP/FCP
const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      //这里的name是为了区分'first-paint','first-contentful-paint'
      const metricName = entry.name;
      const time = Math.round(entry.startTime + entry.duration);
      reportToServer({
        eventCategory: 'Performance Metrics',
        eventAction: metricName,
        eventValue: time,
        nonInteraction: true,
      });
    }
  });
  observer.observe({entryTypes: ['paint']});
复制代码
根据你首屏最重要的元素得到FMP

以前已经介绍过对于浏览器来讲很那准确的知道每一个网站对重要的一块区域显示的时间,那么只有开发者本身可以准确的找到最重要的一块区域得到FMP,假设咱们网站首屏最重要的元素是一个图片就能够这么写.

<img src="important.jpg" onload="performance.clearMarks('img displayed'); performance.mark('img displayed');">
<script> performance.clearMarks("img displayed"); performance.mark("img displayed"); </script>
复制代码
得到TTI

目前在PerformanceObserver中尚未办法得到TTI的接口,经过这个tti-polyfill能够知道这个tti

import ttiPolyfill from 'tti-polyfill.js';

ttiPolyfill.getFirstConsistentlyInteractive().then((tti) => {
  reportToServer({
    eventCategory: 'Performance Metrics',
    eventAction: 'TTI',
    eventValue: tti,
    nonInteraction: true,
  });
});
复制代码
监视长任务

以前提到过,长任务可能会影响浏览器对用户响应速度或者形成动画的卡顿.那么能意识到长任务的存在而且把他缩短是颇有必要的。(长任务API认为50ms以上任务的为长任务)

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    reportToServer({
      eventCategory: 'Performance Metrics',
      eventAction: 'longtask',
      eventValue: Math.round(entry.startTime + entry.duration),
      //这里的长任务会包含一个attribute
      //https://w3c.github.io/longtasks/#sec-TaskAttributionTiming
      eventLabel: JSON.stringify(entry.attribution),
    });
  }
});

observer.observe({entryTypes: ['longtask']});
复制代码
监视响应延迟

长任务会阻塞线程致使浏览器没法响应用户操做,以前也提到过若是能在100ms之内响应用户的操做就不会让用户以为卡顿,那么若是可以监控到你关键交互的响应时间也是颇有必要的

const submitBtn = document.querySelector('#submit');

submitBtn.addEventListener('click', (event) => {
  const lag = performance.now() - event.timeStamp;
  if (lag > 100) {
    reportToServer({
      eventCategory: 'Performance Metric'
      eventAction: 'input-latency',
      eventLabel: '#subscribe:click',
      eventValue: Math.round(lag),
      nonInteraction: true,
    });
  }
});
复制代码
幸存者误差

当咱们的程序若是加载速度很慢(好比加载了过多的js),那么真实用户在网络环境不一致的状况下,有些响应过慢的用户可能早早的在加载完成前就已经退出网站,那么这里就会有一个幸存者误差的问题.你监控的用户都是已经加载完成的用户。为了可以同时检测到退出的用户.

///写在最头部
window.__trackAbandons = () => {
  // 去掉事件监听那么这个方法只执行一次
  document.removeEventListener('visibilitychange', window.__trackAbandons);
  //由于咱们尚未加载report js API 因此咱们要让服务器提供一个post接口在接收此次请求
  const ANALYTICS_URL = 'https://ANALYTICS_URL';
  const TRACKING_ID = 'TRACKING_ID';
  const CLIENT_ID = (Math.random() * Math.pow(2, 52));

  // Send the data to Google Analytics via the Measurement Protocol.
  navigator.sendBeacon && navigator.sendBeacon(ANALYTICS_URL, [
    'v=1', 't=event', 'ec=Load', 'ea=abandon', 'ni=1',
    'dl=' + encodeURIComponent(location.href),
    'dt=' + encodeURIComponent(document.title),
    'tid=' + TRACKING_ID,
    'cid=' + CLIENT_ID,
    'ev=' + Math.round(performance.now()),
  ].join('&'));
};
//visibilitychange能够监听页面unload事件
//https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilitychange_event
document.addEventListener('visibilitychange', window.__trackAbandons);
复制代码

结论

性能对如今的程序愈来愈重要,那么在一个程序须要进行性能优化的时候.我的认为能够按照这样的一个顺序进行:

数据收集->讨论性能指标阀值->针对性能优化->数据从新验证优化结果

这里主要讨论了咱们一些性能指标和收集性能指标的方法,后面会讨论如何针对每一块进行优化。

相关文章
相关标签/搜索