前端監控 API 時使用了 Performace 接口,但是目前大部分文章都只是羅列其本身的屬性或方法,實戰中使用的場景比較少,我自己也走了些彎路,現在記錄下這些,大家可以一起來討論下。
先講一下使用場景,頁面加載後記錄後台接口,頁面跳轉前也記錄後台接口。在記錄接口前需要區分接口是否需要已經被記錄過,不會重複記錄。
就如何標記接口數據是否已被記錄,自己嘗試了四種方式
- 對已記錄的接口添加 outdate 字段並標記為 true
- 使用 performace.mark 方法打標記,每次只記錄最後一個標記後的接口
- 使用 performace.mark 方式打標記,但是比較的是比 mark 的 startTime 字段大的 responseEnd 字段 (比較繞後續看代碼吧)
- 使用全局變量記錄下發送的接口數量,每次先根據變量截取 performace.getEntries() 返回的數組再更新變量的值
1、2 兩種方式被淘汰了,3 當時因時間關係只處理想法階段,後測試可行,4 是目前採用的
下面根據方式來講講遇到的問題
1、performace 只讀
雖然現在大部分的瀏覽器支持在 PerformaceEntry 中增加字段,但有些瀏覽器不允許,如 IE 11、chrome 的部分版本,MDN 中目前也是標記為 只讀
const entries = performance.getEntries();
// 下面方法只篩選了發送的接口,需要過濾掉髮送埋點請求的接口
const freshEntries = entries.filter(
item =>
!item.outdate &&
item.entryType === "resource" &&
item.initiatorType === "xmlhttprequest"
);
entries.forEach(item => {
item.outdate = true;
});
return freshEntries || [];
2、打標記
在打標記時已發送請求但未返回數據的接口,會在接口返回後會出現在標記前。並不會如預期的出現在標記後,原因是 PerformaceEntry 是根據 startTime 排序的
const entries = performance.getEntries();
entries.reverse();
if (entries[0].entryType === 'mark' && entries[0].name === 'MARKNAME') {
return [];
}
// 為防止在這期間有接口請求,先打標記再處理數據
performance.mark('MARKNAME');
const endIndex = entries.findIndex(i => i.entryType === 'mark' && i.name === 'MARKNAME');
const freshEntries = entries
.slice(0, endIndex)
.filter(item => item.entryType === 'resource' && item.initiatorType === 'xmlhttprequest');
return freshEntries || [];
3、打標記後對比 mark 時間和接口返回時間
直接上代碼吧!更簡單直接
const entries = performance.getEntries();
const markList = performance.getEntriesByName('MARKNAME');
markList.reverse();
const markTime = markList.length ? markList[0].startTime : 0;
// 為防止在這期間有接口請求,先打標記再處理數據
performance.mark('MARKNAME');
const freshEntries = entries.filter(
item =>
item.entryType === "resource" &&
item.initiatorType === "xmlhttprequest" &&
item.responseEnd > markTime // 對比接口的返回時間和上次打標記的時間
);
return freshEntries || [];
項目採用的是typeScript,打包時報 Property 'responseEnd' does not exist on type 'PerformanceEntry',對 ts 語法也不是很熟,就先放棄了
4、記錄已發送的接口數量
這個方式很簡單,之所以一開始的時候未採用,是不想創建全局變量,還要截取數組,給字段賦值。後來因時間問題也就只能這樣了。
// 初始化時,alreadySendApiNum 設置為 0
const entries = performance.getEntries();
const freshEntries = entries
.filter(item => item.entryType === 'resource' && item.initiatorType === 'xmlhttprequest');
return freshEntries || [];
freshEntries.slice(alreadySendApiNum)... // 記錄接口數據
alreadySendApiNum = freshEntries.length;
對 performance 的瞭解有限,先到此為止
希望有幫助到屏幕前的你,也望不吝賜教
如有侵權請告知