博客 / 詳情

返回

歷險記 ---- Performance

前端監控 API 時使用了 Performace 接口,但是目前大部分文章都只是羅列其本身的屬性或方法,實戰中使用的場景比較少,我自己也走了些彎路,現在記錄下這些,大家可以一起來討論下。

先講一下使用場景,頁面加載後記錄後台接口,頁面跳轉前也記錄後台接口。在記錄接口前需要區分接口是否需要已經被記錄過,不會重複記錄。

就如何標記接口數據是否已被記錄,自己嘗試了四種方式

  1. 對已記錄的接口添加 outdate 字段並標記為 true
  2. 使用 performace.mark 方法打標記,每次只記錄最後一個標記後的接口
  3. 使用 performace.mark 方式打標記,但是比較的是比 mark 的 startTime 字段大的 responseEnd 字段 (比較繞後續看代碼吧)
  4. 使用全局變量記錄下發送的接口數量,每次先根據變量截取 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 的瞭解有限,先到此為止
希望有幫助到屏幕前的你,也望不吝賜教

如有侵權請告知

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.