前言
作爲前端人員肯定經常遇到這樣的場景:需求剛上線,產品拿着手機來找你,爲什麼頁面打開這麼慢呀,心想自己開發的時候也有注意性能問題呀,不可能會這麼誇張。那沒辦法只能排查下是哪一塊影響了頁面的整體性能,打開瀏覽器控制檯一看,頁面上的這些配圖每張都非常大,心想這些配圖都這麼大,頁面怎麼快,那麼我們有沒有辦法監測頁面上的這些靜態資源大小,從而避免這種情況的發生。
Performance
Performance
接口可以獲取到當前頁面中與性能相關的信息。
該對象提供許多屬性及方法可以用來測量頁面性能,這裏介紹幾個用來獲取PerformanceEntry
的方法:
getEntries
該方法獲取一組當前頁面已經加載的資源PerformanceEntry對象。接收一個可選的參數
options
進行過濾,options
支持的屬性有name
,entryType
,initiatorType
。
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
,用來獲取文檔中資源的計時信息。該類型包括有:script
、link
、img
、css
、xmlhttprequest
、beacon
、fetch
、other
等。
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
自己包了一層,這樣就能夠及時發現線上配置資源是否有問題,並且這個腳本也不需要所有用戶都執行,因爲大家的資源都是一樣的,只需要配置特定白名單(比如開發、測試、產品),在頁面上線後,在進行線上迴歸的同時執行該腳本去監測上線配置資源是否都合理...