載入第三方 JavaScript

Arthur Evans

如果您已最佳化程式碼,但網站載入速度仍過慢,可能是第三方指令碼的問題。

第三方指令碼提供多種實用功能,可讓網頁更具動態、互動性和互連性。其中有些甚至可能對網站功能或收益來源至關重要。但使用這些方法有風險:

  • 這類指令碼可能會降低網站效能。
  • 可能引發隱私權或安全性問題。
  • 他們難以預測,行為可能會有非預期的後果。

理想情況下,您應確保第三方指令碼不會影響網站的重要轉譯路徑。本指南將逐步說明如何找出並修正載入第三方 JavaScript 的相關問題,並盡可能降低使用者面臨的風險。

什麼是第三方指令碼?

第三方 JavaScript 通常是指可直接從第三方供應商嵌入任何網站的指令碼。例如:

  • 社群媒體分享按鈕 (Facebook、X、LinkedIn、Mastodon)

  • 嵌入影片播放器 (YouTube、Vimeo)

  • 廣告 iframe

  • 數據分析和指標指令碼

  • 實驗 A/B 測試指令碼

  • 輔助程式庫,例如日期格式、動畫或功能程式庫

YouTube 影片嵌入範例
YouTube 影片嵌入範例,可使用下列程式碼新增至網頁。
<iframe
  width="560"
  height="315"
  src="https://www.youtube.com/embed/mo8thg5XGV0"
  frameborder="0"
  allow="autoplay; encrypted-media"
  allowfullscreen
>
</iframe>

不過,嵌入第三方指令碼,通常代表我們必須仰賴這些指令碼快速執行,且不會拖慢網頁速度。第三方指令碼是造成效能降低的常見原因,因為資源不受網站擁有者控制,包括下列問題:

  • 向多個伺服器發出過多網路要求。網站需要提出的要求越多,載入時間就可能越長。

  • 傳送過多 JavaScript,導致主執行緒忙碌。JavaScript 過多可能會阻礙 DOM 建構,導致網頁算繪延遲。CPU 密集指令碼剖析和執行作業可能會延遲使用者互動,並導致電池耗電。

  • 傳送大型、未最佳化的圖片檔案或影片,可能會耗用數據流量,並增加使用者費用。

  • 如果網頁載入指令碼時未謹慎處理,可能會造成單點故障 (SPOF) 的安全性問題。

  • HTTP 快取不足,導致瀏覽器必須傳送更多網路要求來擷取資源。

  • 伺服器壓縮不足,導致資源載入速度緩慢。

  • 在處理完成前,系統會封鎖內容顯示。非同步 A/B 測試指令碼也可能發生這種情況。

  • 使用已知會損害使用者體驗的舊版 API,例如 document.write()。

  • DOM 元素過多或 CSS 選取器成本過高。

  • 如果加入多個第三方嵌入項目,可能會導致多個架構和程式庫多次提取,浪費資源並加劇現有效能問題。

  • 第三方指令碼通常會使用嵌入技術,如果伺服器回應緩慢,即使嵌入使用 async 或 defer,也可能會封鎖 window.onload。

能否修正第三方指令碼問題,取決於網站和您設定第三方指令碼載入方式的能力。幸好,有許多解決方案和工具可以找出並修正第三方資源的問題。

如何辨識網頁上的第三方指令碼?

如要最佳化第三方指令碼,首先要找出網站上的第三方指令碼,並判斷其對效能的影響。建議使用免費的網路速度測試工具,包括 Chrome 開發人員工具、PageSpeed Insights 和 WebPageTest,找出耗費資源的指令碼。這些工具會顯示豐富的診斷資訊,指出網站使用的第三方指令碼數量,以及哪些指令碼執行時間最長。

WebPageTest 的瀑布檢視畫面可突顯使用大量第三方指令碼的影響。下圖來自「Tags Gone Wild」,顯示載入網站主要內容所需的網路要求圖表範例,而非追蹤和行銷指令碼。

WebPageTest 的瀑布圖,顯示實際網站與載入追蹤指令碼所花費的時間
這個網頁的指令碼載入時間比網頁本身還長。

WebPageTest 的網域細目也可用於以視覺化方式呈現來自第三方來源的內容數量。並依位元組總數和要求數量細分:

依網域細分的內容 (第一個檢視畫面)。顯示每個第三方的要求和位元組百分比
網域細目圖表會顯示網頁內容有多少來自第三方。

如何評估第三方指令碼對網頁的影響?

如果發現某個指令碼造成問題,請找出該指令碼的作用,並判斷網站是否需要該指令碼才能運作。如有必要,請執行 A/B 測試,在感知價值與對重要使用者參與度或成效指標的影響之間取得平衡。

Lighthouse 啟動時間稽核

Lighthouse 的 JavaScript 啟動時間稽核會醒目顯示指令碼剖析、編譯或評估時間過長的指令碼。這有助於找出會耗用大量 CPU 資源的第三方指令碼。

Lighthouse 顯示支援指令碼評估和剖析
啟動時間稽核會顯示載入時間最長的指令碼。

Lighthouse 網路酬載稽核

Lighthouse 網路酬載稽核會找出網路要求,包括會拖慢網頁載入時間,並導致使用者在行動數據上花費超出預期的第三方網路要求。

Lighthouse 顯示對大型網路酬載的支援
網路酬載稽核會顯示哪些網路要求耗費最多時間,以及擷取最多資料。

Chrome 開發人員工具網路要求封鎖

Chrome 開發人員工具可讓您查看網頁在指定指令碼、樣式表或其他資源無法使用時的行為。這項操作是透過網路要求封鎖功能完成,這項功能可協助評估從網頁中移除個別第三方資源的影響。

如要啟用要求封鎖功能,請在「網路」面板中,對任何要求按一下滑鼠右鍵,然後選取「封鎖要求網址」。接著,DevTools 導覽匣中會顯示要求封鎖分頁,讓您管理已封鎖的要求。

從開發人員工具的「Network」(網路) 面板封鎖要求網址
封鎖個別網路要求,查看網頁在沒有這些要求時的行為。

Chrome 開發人員工具的「Performance」(效能) 面板

Chrome 開發人員工具中的「Performance」面板可協助找出網頁效能問題。

  1. 按一下「錄製」。
  2. 載入網頁。開發人員工具會顯示瀑布圖,呈現網站載入時間的分配情況。
  3. 前往「Performance」面板底部的「Bottom-up」。
  4. 按一下「Group by product」,並依載入時間排序網頁的第三方指令碼。
開發人員工具的「Performance」面板,顯示依 (第三方) 產品分組的「Bottom-up」檢視畫面
第三方指令碼依產品排序,載入時間最長的排在最前面。

如要進一步瞭解如何使用 Chrome 開發人員工具分析載入網頁效能,請參閱「開始分析執行階段效能」。

以下是我們建議的工作流程,可用來評估第三方指令碼的影響:

  1. 使用「網路」面板,評估網頁載入所需時間。
    • 為模擬實際情況,建議您開啟網路節流和 CPU 節流。使用者不太可能擁有快速的網路連線和桌上型電腦硬體,可降低實驗室環境中昂貴指令碼的影響。
  2. 封鎖您認為有問題的第三方指令碼網址或網域 (請參閱 Chrome 開發人員工具的「Performance」(效能) 面板,瞭解如何找出耗費資源的指令碼)。
  3. 重新載入網頁,再次測量載入時間。
    • 為取得更準確的資料,建議您至少測量載入時間三次。這是因為某些第三方指令碼會在每次載入網頁時擷取不同資源。為此,開發人員工具的「效能」面板支援多項記錄。

使用 WebPageTest 評估第三方指令碼的影響

WebPageTest 支援在「Advanced Settings」 >「Block」中,封鎖個別要求載入,以評估其影響。您可以使用這項功能指定要封鎖的網域清單,例如廣告網域。

WebPageTest 進階設定 < 封鎖。顯示文字區域,用於指定要封鎖的網域。
在這個面板中列出要封鎖的網域。

建議您按照下列工作流程使用這項功能:

  1. 測試網頁,不封鎖第三方。
  2. 封鎖部分第三方,然後再次測試。
  3. 從「測試記錄」中選取兩項結果。
  4. 按一下 [Compare] (比較) 。
WebPageTest 顯示比較選項,可讓您比較兩份報表
選取要比較的負載測試結果。

下圖顯示 WebPageTest 的幻燈片功能,比較啟用和未啟用第三方資源的網頁載入序列。建議您在測試個別第三方來源時勾選這個選項,判斷哪些網域對網頁效能的影響最大。

WebPageTest 幻燈片顯示載入網站時,停用和未停用第三方資源的影響
封鎖第三方資源的影響, 摘自 Andy Davies 的 Using WebPageTest To Measure The Impact Of Third-Party Tags 。

WebPageTest 也支援兩項在 DNS 層級運作的指令,可用於封鎖網域:

WebPageTest 也有單點故障 (SPOF) 分頁,可讓您模擬逾時或完全無法載入資源的情況。與網域封鎖不同,SPOF 會慢慢逾時,因此可用於測試第三方服務負載過重或暫時無法使用時,網頁的行為。

WebPageTest 進階設定 > SPOF > 失敗的主機
使用 SPOF 測試功能,模擬指定網域故障的情形。

使用長時間任務偵測耗費大量資源的 iframe

第三方 iframe 中的指令碼如果需要長時間執行,可能會封鎖主執行緒,並延遲其他工作。這些長時間任務可能會導致事件處理常式運作緩慢或影格遺失,進而降低使用者體驗。

如要偵測實際使用者監控 (RUM) 的長時間任務,請使用 JavaScript PerformanceObserver API 觀察 longtask 項目。這些項目包含歸因屬性,可用於判斷造成長時間任務的頁框背景資訊。

下列程式碼會將 longtask 項目記錄到控制台,包括「昂貴」iframe 的項目:

<script>
  const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // Attribution entry including "containerSrc":"https://example.com"
      console.log(JSON.stringify(entry.attribution));
    }
  });

  observer.observe({entryTypes: ['longtask']});
</script>

<!-- Imagine this is an iframe with expensive long tasks -->
<iframe src="https://example.com"></iframe>

如要進一步瞭解如何監控長時間任務,請參閱「以使用者為中心的成效指標」。

如何有效率地載入第三方指令碼?

如果第三方指令碼導致網頁載入速度變慢,您可以採取下列幾種做法來提升效能:

  • 使用 async 或 defer 屬性載入指令碼,避免妨礙文件剖析。
  • 如果第三方伺服器速度緩慢,請考慮自行託管指令碼。
  • 如果指令碼無法為網站帶來明顯價值,請將其移除。
  • 使用 <link rel=preconnect> 或 <link rel=dns-prefetch> 等資源提示,對託管第三方指令碼的網域執行 DNS 查詢。

使用 async 或 defer

JavaScript 執行作業會阻斷剖析器。瀏覽器遇到指令碼時,必須暫停 DOM 建構作業,將指令碼傳遞至 JavaScript 引擎,並允許指令碼執行,然後再繼續建構 DOM。

async 和 defer 屬性會變更這項行為,如下所示:

  • async 會讓瀏覽器在繼續剖析 HTML 文件時,以非同步方式下載指令碼。指令碼下載完成後,系統會在執行指令碼時封鎖剖析作業。

  • defer 會讓瀏覽器在繼續剖析 HTML 文件時,以非同步方式下載指令碼,然後等到文件剖析完成後再執行指令碼。

除非指令碼是重要轉譯路徑的必要項目,否則請一律對第三方指令碼使用 async 或 defer。如果指令碼必須在載入程序中提早執行 (例如某些數據分析指令碼),請使用 async。請針對較不重要的資源使用 defer,例如在網頁上顯示位置低於使用者一開始看到的位置的影片。

如果效能是您的首要考量,建議您等到網頁的重要內容載入後,再加入非同步指令碼。我們不建議將 async 用於 jQuery 等重要程式庫。

部分指令碼必須在不使用 async 或 defer 的情況下載入,尤其是網站的重要部分。包括網站運作不可或缺的 UI 程式庫或內容傳遞網路 (CDN) 架構。

其他指令碼則無法以非同步方式載入。請查看所用指令碼的說明文件,並將無法非同步載入的指令碼替換為可非同步載入的替代指令碼。請注意,有些第三方會建議同步執行指令碼,即使非同步執行效果一樣好。

請注意,async 無法解決所有問題。如果網頁包含大量指令碼 (例如用於廣告目的的追蹤指令碼),即使以非同步方式載入,仍會拖慢網頁載入速度。

使用資源提示縮短連線設定時間

建立與第三方來源的連線可能需要很長的時間,尤其是在網路速度緩慢時,因為網路要求包含多個複雜元件,包括 DNS 查詢和重新導向。您可以使用資源提示 (例如 ),在網頁載入程序初期,對代管第三方指令碼的網域執行 DNS 查詢,以便後續網路要求能更快進行:

<link rel="dns-prefetch" href="http://example.com" />

如果連線的第三方網域使用 HTTPS,您也可以使用 ,同時執行 DNS 查詢和解析 TCP 來回時間,以及處理 TLS 協商。這些步驟可能非常緩慢,因為涉及驗證 SSL 憑證,因此預先連線可大幅縮短載入時間。

<link rel="preconnect" href="https://cdn.example.com" />

使用 iframe「沙箱化」指令碼

如果直接將第三方指令碼載入 iframe,就不會阻擋主網頁執行。AMP 採用這種方法,避免 JavaScript 進入關鍵路徑。請注意,這個方法仍會封鎖 onload 事件,因此請盡量不要將重要功能附加至 onload。

Chrome 也支援權限政策 (舊稱功能政策),這是一組政策,可讓開發人員選擇性停用特定瀏覽器功能的存取權。您可以使用這項功能,防止第三方內容在網站中引入不必要的行為。

自行託管第三方指令碼

如要進一步控管重要指令碼的載入方式,例如縮短 DNS 時間或改善 HTTP 快取標頭,可以自行託管。

不過,自行託管也有其問題,尤其是在更新指令碼時。自行託管的指令碼不會自動更新 API 異動或安全性修正,可能導致收益損失或安全性問題,直到您手動更新指令碼為止。

或者,您可以使用 Service Worker 快取第三方指令碼,進一步控管從網路擷取指令碼的頻率。您也可以使用 Service Worker 建立載入策略,在網頁達到關鍵使用者時刻前,限制非必要的第三方要求。

對較少的使用者進行 A/B 測試

A/B 測試 (或分組對比測試) 是一種實驗技術,可測試兩種版本的網頁,分析使用者體驗和行為。這項工具會向網站流量的不同樣本提供網頁版本,並根據數據分析判斷哪個版本能提供更高的轉換率。

不過,A/B 測試會延遲算繪,以決定要啟用哪項實驗。JavaScript 通常用於檢查使用者是否屬於 A/B 測試實驗,然後啟用正確的變化版本。即使使用者未參與實驗,這個程序也可能導致體驗不佳。

為加快網頁算繪速度,建議您將 A/B 測試指令碼傳送給較少的使用者族群,並在伺服器端執行程式碼,決定要顯示哪個版本的網頁。

延遲載入第三方資源

如果嵌入的第三方資源 (例如廣告和影片) 建構不當,可能會大幅降低網頁速度。延遲載入可用於僅在必要時載入嵌入資源,例如等到使用者捲動到足夠的位置,才在網頁頁尾放送廣告。您也可以在主要網頁內容載入後,但在使用者與網頁互動前,延遲載入第三方內容。

插圖顯示對不需捲動位置體驗至關重要的素材資源,以及較不重要且可延遲載入的素材資源。
您可以延遲載入使用者在載入網頁時不會立即看到的素材資源。

延遲載入資源時請務必小心,因為這通常涉及 JavaScript 程式碼,可能會受到不穩定的網路連線影響。

DoubleClick 的官方說明文件中,提供了延遲載入廣告的操作指南。

使用 Intersection Observer 提高延遲載入效率

過去,為了延遲載入而偵測元素是否在可視區域中顯示的方法容易出錯,而且通常會降低瀏覽器速度。這些低效率的方法通常會監聽 scroll 或 resize 事件,然後使用 getBoundingClientRect() 等 DOM API,計算元素相對於可視區域的位置。

IntersectionObserver 是一種瀏覽器 API,可讓網頁擁有者有效偵測觀察到的元素何時進入或離開瀏覽器的可視區域。LazySizes 也支援 IntersectionObserver。

延遲載入數據分析

如果延遲載入數據分析指令碼的時間過長,可能會錯過寶貴的數據分析資料。幸好,有一些策略可以延遲初始化數據分析,同時保留網頁載入初期的資料。

Phil Walton 的網誌文章「我為每個網站設定的 Google Analytics」介紹了 Google Analytics 的其中一種策略。

安全載入第三方指令碼

本節提供相關指引,協助您盡可能安全地載入第三方指令碼。

建議不要使用 document.write()

第三方指令碼 (尤其是舊版服務) 有時會使用 document.write() 插入及載入指令碼。這會造成問題,因為 document.write() 的行為不一致,且失敗時難以偵錯。

document.write() 問題的修正方式就是不要使用。在 Chrome 53 以上版本中,Chrome 開發人員工具會將 document.write() 的問題記錄到控制台:

開發人員工具控制台警告,醒目顯示第三方嵌入使用 document.write() 的違規行為
Chrome 開發人員工具旗標document.write()使用情形。

如果收到這項錯誤,請檢查傳送至瀏覽器的 HTTP 標頭,確認網站是否使用 document.write()。Lighthouse 也能標出仍在使用 document.write() 的第三方指令碼。

Lighthouse 最佳做法稽核標記 document.write() 的使用
Lighthouse 報表顯示哪些指令碼使用 document.write()。

謹慎使用代碼管理工具

代碼是一段程式碼片段,可讓數位行銷團隊收集資料、設定 Cookie,或將社群媒體小工具等第三方內容整合至網站。這些代碼會將網路要求、JavaScript 依附元件和其他資源新增至網頁,可能會影響網頁效能,而且隨著新增的代碼越來越多,要盡可能減少對使用者的影響也越來越困難。

為確保網頁快速載入,建議使用 Google 代碼管理工具 (GTM) 等代碼管理工具。GTM 可讓您以非同步方式部署代碼,避免代碼載入時互相干擾,減少瀏覽器執行代碼所需的網路呼叫次數,並在資料層 UI 中收集代碼資料。

使用代碼管理工具的風險

雖然代碼管理工具旨在簡化網頁載入作業,但如果使用不當,反而可能導致網頁載入速度變慢,原因如下:

  • 如果代碼管理工具中的代碼和自動事件監聽器過多,瀏覽器會發出不必要的網路要求,並降低程式碼快速回應事件的能力。
  • 只要具備憑證和存取權,任何人都能在代碼管理工具中新增 JavaScript。這不僅會增加載入網頁所需的昂貴網路要求數量,還可能因不必要的指令碼而帶來安全風險和其他效能問題。為降低這些風險,建議您限制代碼管理工具的存取權。

避免指令碼汙染全域範圍

第三方指令碼可能會以各種方式運作,導致網頁意外中斷:

  • 載入 JavaScript 依附元件的指令碼可能會以與程式碼互動不佳的程式碼,污染全域範圍。
  • 非預期的更新可能會導致破壞性變更。
  • 第三方程式碼在傳輸過程中可能會遭到修改,導致網頁在測試和部署階段的行為不同。

建議您定期稽核載入的第三方指令碼,檢查是否有惡意行為。您也可以實作自我測試、子資源完整性,以及安全傳輸第三方程式碼,確保網頁安全。

緩解策略

以下提供一些大規模策略,可盡量減少第三方指令碼對網站效能和安全性的影響:

  • HTTPS:使用 HTTPS 的網站不得依賴使用 HTTP 的第三方。詳情請參閱「混合內容」。

  • 沙箱機制:建議您在 iframe 中使用 sandbox 屬性執行第三方指令碼,限制指令碼可執行的動作。

  • 內容安全政策 (CSP):您可以在伺服器回應中使用 HTTP 標頭,定義網站信任的指令碼行為,並偵測及減輕某些攻擊的影響,例如跨網站指令碼 (XSS)。

以下範例說明如何使用 CSP 的 script-src 指令,指定網頁允許的 JavaScript 來源:

// Given this CSP header Content-Security-Policy: script-src
https://example.com/ // The following third-party script will not be loaded or
executed

<script src="https://not-example.com/js/library.js"></script>

延伸閱讀

如要進一步瞭解如何最佳化第三方 JavaScript,建議您參閱下列文章:

感謝 Kenji Baheux、Jeremy Wagner、Pat Meenan、Philip Walton、Jeff Posnick 和 Cheney Tsai 協助審查。