優化 JavaScript 資源以提高頁面速度

已發表: 2020-05-05

下面的示例來自一個大型、複雜的新聞網站。 他們多年來一直在失去自然流量。 它們的 DOMContentLoaded 事件時間為 2615.2 MS。 您可能認為他們的 DOM 大小非常龐大,但沒有……

和谷歌推薦的差不多,本文檔中只有 1230 個 HTML 節點。

您可以使用 DevTools 計算您的 domContentLoaded 事件時間和流程,並將其與您的競爭對手進行比較。

檢查此示例表明 DOM 大小不一定是關鍵點。 這裡,主要問題是資源順序:“主選項卡”中的藍色部分用於 HTML 解析。 但是,該網站在 HTML 解析過程完成之前通過 JavaScript 渲染中斷了瀏覽器。

(您也可以使用調用樹部分來幫助您的 IT 團隊找到類似的錯誤。)

這個例子清楚地說明了優化 JavaScript 資產的重要性,以及當您在頁面速度優化中忽略 JavaScript 時會出現什麼問題。

這是四篇系列文章中的第三篇。 為了更好地理解本文,您可能需要閱讀該系列的前兩篇文章:

  • Javascript 渲染和頁面速度與瀏覽器的渲染引擎如何創建網頁密切相關。
  • 在閱讀本文之前,您還應該了解高級頁面速度指標。

我將使用前兩篇文章中的一些示例來幫助提供本文的上下文。

什麼是 Javascript 渲染以及它如何影響您的頁面速度?

Javascript 渲染是最後一個頁面加載部分,它可以交互地更改使用 DOM 和 CSSOM 創建的結構。 任何頁面元素都可以以用戶可觸發的格式更改或正常顯示。 任何具有 display:none 屬性且無法被渲染樹訪問的元素都可以使用 JavaScript 渲染為可見,或者通過不同的 HTML 元素注入到 DOM 中。

JavaScript 會中斷 DOM 和 CSSOM,因為它會在瀏覽器讀取 DOM 和 CSSOM 時更改它們。 因此,為了避免對頁面加載時間和速度產生負面影響,有必要檢查 DOM、CSSOM 和 JavaScript 渲染之間的關係。

上面是一個渲染樹的例子。 CSSOM 和 HTML 節點中的所有互鎖代碼片段在渲染樹中都有語義等價物。 如果您仔細觀察,您會注意到“Action Button”HTML 節點不在渲染樹中。 主要原因是“display:none;” CSS 屬性。 由於這個不可見命令,它不包含在渲染樹中。 要了解此樹中的元素是如何構建的,您可能需要閱讀本系列的第一篇文章。

如果您有許多頁面元素不會在第一次加載時出現,因為它們取決於用戶行為,那麼在資源加載順序中,您必須將這些項目分開並將它們放在最後一行。 此時使用影子 DOM 或虛擬 DOM 是更好的選擇。

JavaScript 資源的延遲和異步屬性

如果您將 JS 文件放入該部分並且不使用 'defer' 或 'async' 屬性,它可能會延遲您的 DOMContentLoaded 時間。 為了防止這種情況,我們可以使用這兩個屬性。 Defer 是延遲 JS 文件的加載過程,而 'Async' 是並行加載 JS 和其他源。 兩者都有優點和缺點。 我們將在這裡只討論主要的。

  • 如果您在主 JS 文件上使用 defer,則在安裝之前您可能不會看到它的“啟動器”效果。
  • 如果使用 defer 過多,可能會導致頁面加載結束時出現 CPU 瓶頸。

自撰寫本文以來,Chrome 80 更新已發布。 在 Initiator 列中,現在更容易查看哪個資源被哪個資源調用。 例如,你可以看到一個由 JS 調用的圖像或 CSS 文件。 如果您通過按住 shift 鍵滾動資源,您還將看到在不加載其他資源的情況下無法使用哪個資源。

按住 shift 鍵滾動:紅色表示以綠色突出顯示的資源的條件資源。

您還可以使用 Chrome 中的新發起程序部分來獲得更詳細的資源加載順序、發起程序和優先級審查。 這使您可以檢測到極長且成本高昂的 JS 調用鏈,如下所示。

來自同一站點的長且昂貴的 JS 調用鏈示例。 所選資源上方是其啟動器。 下一部分顯示由所選資源啟動的資源。

  • 延遲的 JS 文件是在 domInteractive 事件之後下載的,所以你需要根據你的 CSS 文件和圖片來選擇它們。
  • 如果您延遲某些用戶跟踪器 3rd 方 JS 文件,您可能無法跟踪某些用戶行為。
  • Defer 通常不會阻塞 DOM 進程,但 Async 會。 具有異步屬性的 JS 文件在 HTML 解析和 CSSOM 處理期間由瀏覽器下載。
  • 如果你過多地使用 async 屬性,可能會造成 CPU 處理瓶頸,並且會減慢 DOM 和 CSSOM 進程。 您需要仔細選擇要延遲或異步的內容。

這是 async 和 defer 屬性的示例方案。 第一個在 domContentLoaded 之前加載,在獲取期間不拆分 HTML 解析。 第二種,在 HTML 解析完成之前,不執行獲取的 JS 文件。

Javascript 渲染和性能的建議和技巧

在開始實踐示例之前,這裡有一些提高 JavaScript 渲染性能的建議。 這也可能有助於更好地了解頁面速度和瀏覽器的工作方式。

不要使用不必要的變量。

如果您是 SEO,您可能會注意到 JavaScript 文件中不必要或未使用的變量。 有許多工具可用於檢測此類錯誤。 您將在下面找到未使用和不必要的變量的兩個基本示例。

var carName=品牌+””+年份;
document.getElementById(“demo”).innerHTML = carName;

這裡,變量“carName”是不必要的。 您可以建議進行以下修改:
document.getElementById(“demo”).innerHTML = 品牌+ ” ” + 年份

或者:

[a, b, c, d, e].forEach(function (value, index) {
控制台.log(索引);
});

這裡,“value”參數不是必需的,因為它沒有被使用。 您可以刪除它:
[a, b, c, d, e].forEach(function (index) {
控制台.log(索引);
});

在右側,您可以看到更長的連接時間(白線),並且由於“異步”Javascripts,CSS 和 JS 文件以不對稱的順序加載。

在左側,連接時間更短,並且 CSS 和 JS 文件沒有混合,因為每個源都是按行加載的。 異步屬性會降低您的 Speed Index,因為它可以延長 TBT 時間,因此您需要進行調查並將其報告給您的開發團隊,以獲取性能選項卡中的性能跟踪器 JS 文件,或者您可以自己運行一些實驗。

使用工具完成困難的任務

對於代碼初學者來說,找到不必要或未使用的變量可能很困難。 您可能希望使用一些工具來完成這些任務,例如 Chrome DevTools 或 Node.js 包,例如 Unused(Kami/node-unused:報告代碼中已定義但未使用的變量的模塊。或用於更多未使用的變量)。 如果您發現甚至是一些小錯誤,我相信您的 IT 團隊會傾聽您的意見,讓您的 JavaScript 文件變得更好。

使用 Chrome DevTools 覆蓋率報告查找未使用的 JavaScript 代碼

Chrome DevTools 覆蓋率報告顯示了未使用的 JavaScript 代碼片段,但它不是很實用。 您可能認為您可以從代碼中刪除每個紅色部分,但事實並非如此……相反,您應該為大量類別頁面找到完全未使用的函數或變量。 這樣,您的開發團隊可以被說服使用 TreeShaking 過程。

TreeShaking 意味著從文件中刪除死代碼。 我建議學習使用未使用的 JS 變量和函數查找器包,以獲得時間。

較小的 DOM 大小也有助於 JavaScript 渲染。 每個 (getElementsByTagName) 命令都會掃描你的 DOM。 在呈現 JavaScript 時,較小的 DOM 大小將需要較少的瀏覽器資源和設備的 CPU/網絡。

隨著新的 Chrome 80 更新,覆蓋報告也發生了變化。 他們添加了可選的 Per Function 和 Per Block 選項。 每塊是這裡的默認值。

如果您選擇 Per Function,您會在報告中看到很大的不同。 出現這種情況的主要原因是 Per Function 視圖檢查是否所有函數都在使用。 如果正在使用 95% 的函數,則 Per Function 選項會將其定義為未使用的代碼,因為 5% 的代碼未使用,儘管函數的大部分已使用。

壓縮、縮小或醜化您的 JS 文件。

這可以通過兩種方式完成。 首先,刪除空格和不必要的註釋。 其次,為您的 JS 文件使用改進的 JavaScript 運算符,並使用現成的技術來修改名稱、變量、函數。

您應該了解用於這種壓縮的箭頭函數。 例如,代替這個 84 個字符的示例:

函數箭​​頭 Islev (a, b) {
控制台.log (a + b);
}
箭頭Fonksiyon (5, 6);

您可以使用箭頭函數將其壓縮為僅 50 個字符 =>
常量 ab = (a, b) => b + a;
console.log (ab (5, 6));

另一種縮短/壓縮方法對 If 語句有效。 而不是這個 63 個字符的代碼片段:
如果 (a<b) {
控制台.log(ab);
}
別的 {
控制台.log(a+b);

您可以使用下面的 43 個字符:
(a<b) ? 控制台.log(ab) : 控制台.log(a+b);

您還可以向您的 IT 團隊建議他們使用 $ 和 _ 符號進行壓縮。 大多數 JavaScript 文件都用於重新解釋 DOM。 對此,您可能會看到很多 document.getElementById(x); 文件中的代碼片段。 您可以為此任務使用 $ 符號。 這將使您免於一大堆無用的大小。

大多數 JavaScript 庫默認使用 $ 來定義函數,但不是全部,因為 $ 也是一個字母字符。

在這種情況下,您可能會建議您的 IT 團隊使用:
函數 $(x) {return document.getElementById(x);} 。

使用適當的渲染類型

就 SEO 兼容性而言,JavaScript 和網頁呈現類型。
SSR Hydration 意味著一些 JS 組件將使用客戶端渲染進行渲染。 它對 FP 和 FMP 很有用,但 TTI 和速度指數得分可能有一些缺點。
圖片來源:Notprovided.eu

JavaScript 渲染性能的編碼最佳實踐

  • 另一個重要的壓縮貢獻來自“_”的使用。 您可以使用“underscore.js”來改進 JavaScript 編寫格式和功能。 通過這種方式,您將創建更小的 JS 文件,同時使用更短的 JS 函數來操作列表和集合,而無需內置 JS 函數。
  • 使用大量冗長而費力的變量更改和全局變量污染也是渲染緩慢的根源。 您應該確定函數的一般範圍選擇和全局變量/長變量類型。 使用帶有“Let”的局部變量更適合渲染。 由於局部變量,瀏覽器不會審核其他全局函數變量以進行下一次更改。

為了模擬更真實的性能檢查,例如您可能在低端手機上看到的內容,您應該使用 Chrome DevTools 中的 CPU Throttling 和 Fast/Slow 3G Connection 首選項。
圖片來源:Addy Osmani

  • 使用較小的 JS 函數和變量鏈將有助於您的渲染性能。 此外,使用“this”選擇器而不是“with”選擇器會更好。 Javascript 中的“this”選擇器是一個本地功能代碼,與“with”不同,let 和 var 的相同邏輯在這裡也有效。
  • 如果你在 For 循環代碼片段中使用你的語句,這也會稍微降低你的渲染速度。 因為您的函數語句將遍歷循環的每個元素。 您可以簡單地為循環元素創建一個新變量,並且可以使用 For 循環之外的函數調用這些元素。
  • 如果你想多次訪問一個 HTML 元素,你可以為它創建一個變量,然後你可以用你想要的函數調用它。 使用 JavaScript 訪問 HTML 元素並不是一個快速的過程。 您可能只是為您的瀏覽器增加了負擔。

提高 Javascript 渲染性能的另一種方法是通過 Service Worker 進行三態渲染。 您可以將一些 JS 文件放入客戶端的瀏覽器內存中以備將來使用。 這樣,您可以使您的網站離線工作。
您可以在這裡找到一個簡單的演示,以便更好地理解和與服務人員一起練習的機會

綁起來:優化 JavaScript 和頁面速度如何影響 SEO

為了防止 JavaScript 資產破壞您的頁面速度,我們已經看到了 Defer 和 Async 如何產生巨大的影響。 我們還研究了一些“調試”策略和編碼技巧,它們可以幫助您使用 JavaScript 資源提高頁面的速度。

既然我們已經了解了瀏覽器如何構建網頁,頁面速度是如何衡量和影響的,以及優化 JavaScript 在頁面加載時間中所起的作用,下一篇文章將演示資源加載順序如何影響頁面速度和爬取預算。

如果您有興趣回顧本系列四篇文章中的前幾篇文章,可以在這裡找到它們:

  • “瀏覽器如何創建網頁”
  • “高級頁面速度指標”。
開始免費試用