載入第三方 JavaScript

Addy Osmani
Addy Osmani
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 選取器。

  • 加入多個第三方嵌入內容可能會導致多次拉取多個架構和程式庫,造成資源浪費,並使現有效能問題更加嚴重。

  • 第三方指令碼通常會使用嵌入技巧,如果伺服器回應速度緩慢,這些技巧可能會阻擋 window.onload,即使嵌入程式碼使用非同步或延遲也不例外。

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

如何在網頁上找出第三方指令碼?

找出網站上的第三方指令碼,並判斷其對效能造成的影響,是改善這些指令碼的第一步。建議您使用免費的網頁速度測試工具,包括 Chrome 開發人員工具PageSpeed InsightsWebPageTest,找出耗用大量資源的指令碼。這些工具會顯示豐富的診斷資訊,讓您瞭解網站使用了多少第三方指令碼,以及哪些指令碼執行所需的時間最長。

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

來自網頁測試的瀑布圖檢視畫面,顯示實際網站與載入追蹤指令碼所花費的時間
這個頁面上的指令碼載入時間比頁面本身還要長。

WebPageTest 的網域分類功能,也可用來視覺化第三方來源的內容量。並依據總位元組和要求數量進行細分:

依網域劃分的內容 (首次觀看)。顯示每個第三方的要求和位元組百分比
網域細目圖表會顯示網頁內容中來自第三方的比例。

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

如果發現有指令碼導致問題,請找出該指令碼的作用,並判斷網站是否需要該指令碼才能運作。如有需要,請執行 A/B 版本測試,以便平衡其感知價值與對主要使用者參與度或成效指標的影響。

Lighthouse 啟動時間稽核

Lighthouse 的 JavaScript 啟動時間稽核會標示耗費大量時間剖析、編譯或評估的腳本。這有助於您找出會耗用大量 CPU 資源的第三方指令碼。

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

Lighthouse 網路酬載稽核

Lighthouse 的網路酬載審查會找出網路要求,包括會減緩網頁載入時間和導致使用者在行動數據上花費超出預期的第三方網路要求。

Lighthouse 顯示支援大型網路酬載
「Network Payloads Audit」會顯示哪些網路要求耗費最多時間,以及擷取最多資料。

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

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

如要啟用要求封鎖功能,請在「Network」面板中按一下任何要求,然後選取「Block Request URL」。接著,開發人員工具匣會顯示「請求封鎖」分頁,讓您管理已封鎖的請求。

透過開發人員工具網路面板封鎖要求網址
封鎖個別網路要求,查看網頁在沒有這些要求的情況下如何運作。

Chrome 開發人員工具效能面板

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

  1. 按一下「錄製」
  2. 載入網頁。開發人員工具會顯示瀑布圖表,代表網站的載入時間。
  3. 前往「成效」面板底部的「自下而上」
  4. 按一下「依產品分組」,並依載入時間排序網頁的第三方指令碼。
開發人員工具「Performance」面板,顯示以 (第三方) 產品分組的「Bottom-up」檢視畫面
第三方指令碼依產品排序,從載入時間最長的開始。

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

以下是評估第三方指令碼影響的建議工作流程:

  1. 使用「Network」面板,評估網頁載入所需的時間。
    • 為了模擬實際情況,建議您開啟網路節流CPU 節流。您的使用者不太可能擁有快速的網路連線和電腦硬體,因此無法在實驗室條件下減少高耗用資源的指令碼影響。
  2. 封鎖您認為有問題的第三方指令碼所屬網址或網域 (如需瞭解如何找出耗用大量資源的指令碼,請參閱 Chrome 開發人員工具效能面板)。
  3. 重新載入頁面,然後再次測量載入時間。
    • 為獲得更準確的資料,您可能需要至少測量三次載入時間。這可說明為何某些第三方指令碼會在每次載入網頁時擷取不同的資源。為協助您完成這項工作,DevTools 效能面板支援多個錄製作業。

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

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

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

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

  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>

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

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

如果第三方指令碼導致網頁載入速度變慢,您可以透過以下幾種方式改善效能:

  • 請使用 asyncdefer 屬性載入指令碼,避免阻斷文件剖析作業。
  • 如果第三方伺服器速度緩慢,建議您自行代管指令碼。
  • 如果程式碼無法為您的網站帶來明顯價值,請將其移除。
  • 使用 <link rel=preconnect><link rel=dns-prefetch>資源提示,為託管第三方指令碼的網域執行 DNS 查詢。

使用 asyncdefer

JavaScript 執行作業會遭到剖析器封鎖。瀏覽器遇到指令碼時,必須暫停 DOM 建構作業、將指令碼傳遞至 JavaScript 引擎,並在繼續執行 DOM 建構作業前,允許指令碼執行。

asyncdefer 屬性會變更此行為,如下所示:

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

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

請一律使用 asyncdefer 來處理第三方指令碼,除非該指令碼對關鍵轉譯路徑而言是必要的。如果需要在載入程序中盡早執行指令碼 (例如某些分析指令碼),請使用 async。請將 defer 用於較不重要的資源,例如在頁面上顯示的影片,使用者一開始不會看到這些影片。

如果您最在意效能,建議您等到網頁的重要內容載入後,再新增非同步指令碼。我們不建議將 async 用於 jQuery 等必要程式庫。

有些指令碼必須在沒有 asyncdefer 的情況下載入,尤其是網站中的重要指令碼。包括網站無法運作的 UI 程式庫或內容傳遞網路 (CDN) 架構。

其他指令碼如果以非同步方式載入,就無法運作。請查看您使用的所有指令碼說明文件,並將無法非同步載入的指令碼,替換為可非同步載入的替代指令碼。請注意,即使非同步執行指令碼也能正常運作,但部分第三方仍建議同步執行指令碼。

請注意,async 無法解決所有問題。如果網頁包含大量指令碼 (例如用於廣告的追蹤指令碼),即使以非同步方式載入,也無法避免這些指令碼減緩網頁載入速度。

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

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

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

如果您要連線的第三方網域使用 HTTPS,您也可以使用 ,該函式會執行 DNS 查詢,並解析 TCP 往返通訊,以及處理 TLS 協商。這些其他步驟可能會非常緩慢,因為它們涉及 SSL 憑證的驗證,因此預先連線可大幅縮短載入時間。

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

使用 iframe 的「Sandbox」指令碼

如果您將第三方指令碼直接載入 iframe,則不會阻止執行主頁面。AMP 會使用這種方法,將 JavaScript 排除在關鍵路徑之外。請注意,這種做法仍會封鎖 onload 事件,因此請勿將重要功能附加至 onload

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

自行託管的第三方指令碼

如要進一步控管重要指令碼的載入方式 (例如減少 DNS 時間或改善 HTTP 快取標頭),您可以自行代管指令碼。

不過,自行代管服務會有自身的問題,尤其是在更新指令碼時。自行代管的指令碼不會自動更新 API 變更或安全性修正,因此可能導致收益損失或安全性問題,除非您手動更新指令碼。

您也可以使用服務工作者快取第三方指令碼,進一步控制從網路擷取指令碼的頻率。您也可以使用服務工作者建立載入策略,以便在頁面達到重要使用者時刻之前,限制非必要的第三方要求。

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

A/B 測試 (或稱為分割測試) 是一種實驗方法,可嘗試使用兩個版本的網頁來分析使用者體驗和行為。這項工具會將網頁版本提供給網站流量的不同樣本,並根據分析結果判斷哪個版本的轉換率較高。

不過,A/B 測試會延遲轉譯,以便決定要啟用哪些實驗。JavaScript 通常用於檢查使用者是否屬於 A/B 版本實驗,然後啟用正確的變化版本。即使使用者未參與實驗,這項程序也可能會讓他們的體驗變差。

為加快網頁轉譯速度,建議您將 A/B 測試指令碼傳送至較小的使用者群組樣本,並執行決定要顯示哪個網頁版本的程式碼。

延遲載入第三方資源

內嵌第三方資源 (例如廣告和影片) 的建構不當,可能會是導致網頁速度變慢的主要原因。延遲載入功能只能在必要時用於載入嵌入式資源,例如等到使用者捲動到足以看到廣告的頁面底部時,才在頁面底部放送廣告。您也可以在主要網頁內容載入後,但在使用者可能與網頁互動之前,延遲載入第三方內容。

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

請小心使用延後載入資源,因為這類操作通常會涉及 JavaScript 程式碼,而這類程式碼可能會受到不穩定的網路連線影響。

DoubleClick 在官方說明文件中提供指引,說明如何在其中延後載入廣告。

使用 Intersection Observer 進行高效延遲載入

以往,用於偵測元素是否在檢視區中顯示 (以便延後載入) 的方法,容易發生錯誤,且經常會讓瀏覽器速度變慢。這些效率不彰的方法通常會監聽 scrollresize 事件,然後使用 getBoundingClientRect() 等 DOM API 來計算元素相對於檢視區的位置。

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

延遲載入數據分析

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

Phil Walton 的部落格文章「The Google Analytics Setup I Use on Every Site I Build」(我建立的每個網站都會使用的 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 的第三方。詳情請參閱混合內容

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

  • 內容安全政策 (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 提供意見。