如何定位瀏覽器頁面崩潰的問題

記得要微笑發表於2022-02-27

問題現象

在實際專案開發中,我們常常會遇到類似如下頁面崩潰的問題,導致瀏覽器頁面崩潰的原因一般都是JS Heap堆記憶體溢位,但此類問題一般控制檯都不會報錯,所以其定位問題的經驗和手段很關鍵,下文是我在實際專案中遇到問題的總結。

頁面崩潰1.gif

問題定位

首先,說一下專案技術棧背景,是採用React+Mobx+single-react-spa搭建的一個微前端中後臺應用。當初始化載入完頁面,點選”刪除“觸發事件後頁面就卡死,過一會兒直接崩潰,但是控制檯沒有任何報錯資訊,定位問題無從下手。思考片刻後,決定採用最基本的方法試一試,刪除事件會刪除表格源資料,會觸發表格元件以及其部分子孫元件的重新渲染,在每一個會重新渲染的元件以及元件內部定義和使用的函式體中加上斷點,最後斷點除錯發現getParentClassName方法體內部陷入死迴圈,當currentElement=null時,while迴圈體就陷入死迴圈

/** 獲取所有父節點的className */
export const getParentClassName = (element: Element, fatherClassName?: string) => {
  const classNames = [];
  let currentElement = element;

  classNames.push(currentElement?.className || '');

  if (fatherClassName) {
    while (
      !(currentElement?.className || '').includes(fatherClassName) &&
      currentElement !== document.body
    ) {
      classNames.push(currentElement?.className || '');
      currentElement = currentElement?.parentElement as Element;
    }
  } else {
    while (currentElement !== document.body) {
      classNames.push(currentElement?.className || '');
      currentElement = currentElement?.parentElement as Element;
    }
  }

  classNames.push(currentElement?.className || '');

  return classNames;
};

因為無法定位引發問題的程式碼塊,上面除錯方法就像黑盒測試一樣,比較消耗時間。後來想了一下,其實我們可以使用performance記錄整個觸發刪除事件後的棧幀(Stack Frame)執行情況

image-20220226155912563.png

image-20220226160032937.png

image-20220226160125088.png

我們可以明顯發現getParentClassName方法死迴圈了,JS Heap從開始的28.3M上升到747M,方法執行耗時佔比84.9%。這種定位方法比手工斷點的定位方法會快出很多,很值得各位同學借鑑。

相關文章