【效能監控】如何有效監測網頁靜態資源大小?

南玖發表於2024-04-24

前言

作為前端人員肯定經常遇到這樣的場景:需求剛上線,產品拿著手機來找你,為什麼頁面開啟這麼慢呀,心想自己開發的時候也有注意效能問題呀,不可能會這麼誇張。那沒辦法只能排查下是哪一塊影響了頁面的整體效能,開啟瀏覽器控制檯一看,頁面上的這些配圖每張都非常大,心想這些配圖都這麼大,頁面怎麼快,那麼我們有沒有辦法監測頁面上的這些靜態資源大小,從而避免這種情況的發生。

Performance

Performance 介面可以獲取到當前頁面中與效能相關的資訊。

該物件提供許多屬性及方法可以用來測量頁面效能,這裡介紹幾個用來獲取PerformanceEntry的方法:

getEntries

該方法獲取一組當前頁面已經載入的資源PerformanceEntry物件。接收一個可選的引數options進行過濾,options支援的屬性有nameentryTypeinitiatorType

const entries = window.performance.getEntries();

getEntriesByName

該方法返回一個給定名稱和 name 和 type 屬性的PerformanceEntry物件陣列,name的取值對應到資源資料中的name欄位,type取值對應到資源資料中的entryType欄位。

const entries = window.performance.getEntriesByName(name, type);

getEntriesByType

該方法返回當前存在於給定型別的效能時間線中的物件PerformanceEntry物件陣列。type取值對應到資源資料中的entryType欄位。

const entries = window.performance.getEntriesByType(type);

嘗試獲取靜態資源資料

使用getEntriesByType獲取指定型別的效能資料,performance entryType中有一個值為resource,用來獲取文件中資源的計時資訊。該型別包括有:scriptlinkimgcssxmlhttprequestbeaconfetchother等。

const resource = performance.getEntriesByType('resource')
console.log('resource', resource)

這樣可以獲取到非常多關於資源載入的資料:

為了方便檢視,我們來稍微處理下資料

const resourceList = []
const resource = performance.getEntriesByType('resource')
console.log('resource', resource)
resource.forEach((item) => {
  resourceList.push({
    type: item.initiatorType, // 資源型別
    name: item.name, // 資源名稱
    loadTime: `${(item.duration / 1000).toFixed(3)}s`, // 資源載入時間
    size: `${(item.transferSize / 1024).toFixed(0)}kb`, // 資源大小
  })
})

這樣對於每個資源的型別、名稱、載入時長以及大小,都非常清晰

但是有些資源的大小為什麼會是0呢?以及還有很多頁面上的資源貌似沒有統計到,這是為啥呢?🤔

這是因為頁面上的資源請求並不是一次性載入完的,比如一些資源的懶載入,這裡就有可能會統計不到,或者資源大小統計會有問題,所以我們需要監聽資源的動態載入

監聽資源載入

以上介紹的3個API都無法做到對資源動態載入的監聽,這裡就需要用到PerformanceObserver來處理動態載入的資源了

PerformanceObserver

PerformanceObserver 主要用於監測效能度量事件,在瀏覽器的效能時間軸記錄新的 performanceEntry 時會被通知。

透過使用 PerformanceObserver() 建構函式我們可以建立並返回一個新的 PerformanceObserver 物件,從而進行效能的監測。

用法

PerformanceObserver 與其它幾個 Observer 類似,使用前需要先進行例項化,然後使用 observe 監聽相應的事件

function perf_observer(list, observer) {
  // ...
}
var observer = new PerformanceObserver(perf_observer);
observer.observe({ entryTypes: ["resource"] });

它主要有以下例項方法:

  • observe:指定監測的 entry types的集合。當 performance entry 被記錄並且是指定的 entryTypes 之一的時候,效能觀察者物件的回撥函式會被呼叫。
  • disconnect:效能監測回撥停止接收PerformanceEntry。
  • takeRecords:返回當前儲存在效能觀察器的 performance entry列表,並將其清空。

嘗試獲取頁面圖片載入資訊

new PerformanceObserver((list) => {
  list
    .getEntries()
    .filter(
    (entry) =>
    entry.initiatorType === 'img' || entry.initiatorType === 'css',
  )
    .forEach((entry) => {
    resourceList.push({
      name: entry.name, // 資源名稱
      loadTime: `${(entry.duration / 1000).toFixed(3)}s`, // 資源載入時間
      type: entry.initiatorType, // 資源型別
      size: `${(entry.transferSize / 1024).toFixed(0)}kb`, // 資源大小
    })
    console.log('--', resourceList)
  })
}).observe({ entryTypes: ['resource'] })

這裡需要注意的是,獲取型別除了img還得加上css,因為CSS中可能會有透過url()載入的背景圖。

這樣,頁面上的圖片大小以及載入時長一目瞭然了

通知

我們自己是知道問題了,但是還要將這些資訊推送給產品及運營,這個可以透過企業微信提供的API來進行操作,不滿足條件的資源將進行推送通知:

setTimeout(() => {
  axios.get('http://127.0.0.1:3000/jjapi/user/pushMessage', {
    params: {
      msgtype: 'markdown',
      markdown: {
        content: `
          <font color="warning">H5專案資源載入異常,請注意檢視</font>
          型別:<font color="comment">圖片資源大小超出限制</font>
          異常數量:<font color="comment">${resourceList.length}例</font> 
          異常列表:<font color="comment">${resourceList.map(
            (item) => item.name,
          )}</font>`,
      },
    },
  })
}, 8000)

通知如下:

這裡為了避免跨域,使用nest自己包了一層,這樣就能夠及時發現線上配置資源是否有問題,並且這個指令碼也不需要所有使用者都執行,因為大家的資源都是一樣的,只需要配置特定白名單(比如開發、測試、產品),在頁面上線後,在進行線上迴歸的同時執行該指令碼去監測上線配置資源是否都合理...

相關文章