前端性能優化一:性能指標

若是咱們想要提升咱們的前端性能,那麼首先你得先只知道怎麼測量你的前端性能。可是哪些前端的性能指標咱們應該關注呢? 在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);
複製代碼

結論

性能對如今的程序愈來愈重要,那麼在一個程序須要進行性能優化的時候.我的認爲能夠按照這樣的一個順序進行:

數據收集->討論性能指標閥值->針對性能優化->數據從新驗證優化結果

這裏主要討論了咱們一些性能指標和收集性能指標的方法,後面會討論如何針對每一塊進行優化。

相關文章
相關標籤/搜索