載入第三方 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 的瀑布檢視畫面可顯示大量使用第三方指令碼的影響。下圖中的標記 Gone Wild 圖片顯示載入網站主要內容所需的網路要求範例圖表,而非追蹤和行銷指令碼。

網頁測試的刊登序列檢視畫面
顯示實際網站與載入追蹤指令碼所花的時間
此網頁上的指令碼載入時間會比網頁本身更長。

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

依網域 (首次查看) 細分的內容。顯示各個第三方的要求和位元組數百分比
網域明細圖表會顯示有多少網頁內容來自第三方。

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

發現有問題的指令碼時,請找出指令碼的用途,並判斷網站是否需要該指令碼才能正常運作。如有需要,請執行 A/B 測試,在所發現的值與對關鍵使用者參與度或成效指標的影響之間,取得平衡。

Lighthouse 開機時間稽核

Lighthouse 的 JavaScript 開機時間稽核功能會醒目顯示具有高成本指令碼剖析、編譯或評估時間的指令碼。這可協助您找出耗用大量 CPU 的第三方指令碼。

Lighthouse 支援指令碼評估及剖析
開機時間稽核會顯示哪些指令碼的載入時間最長。

Lighthouse 網路酬載稽核

Lighthouse 網路酬載稽核功能可識別網路要求,包括降低網頁載入時間及使用者花費超過行動數據流量的第三方網路要求。

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

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

Chrome 開發人員工具會顯示網頁在無法使用指定指令碼、樣式表或其他資源時的行為。這使用網路要求封鎖功能,這項功能可協助您評估從網頁上移除個別第三方資源的影響。

如要啟用要求封鎖功能,請在「Network」面板中的任何要求上按一下滑鼠右鍵,然後選取「Block Request URL」。開發人員工具導覽匣中接著會顯示「要求封鎖」分頁,方便您管理哪些要求遭到封鎖。

透過開發人員工具的「網路」面板封鎖要求網址
封鎖個別網路要求,查看網頁在沒有這類要求的情況下的行為。

Chrome 開發人員工具效能面板

Chrome 開發人員工具的效能面板可協助您找出網頁效能相關問題。

  1. 按一下「Record」(記錄)
  2. 載入網頁。開發人員工具會顯示瀑布圖,呈現網站花費的載入時間。
  3. 前往「效能」面板底部的「由下往上」
  4. 按一下「Group by product」(依產品分組),然後按照載入時間排序網頁上的第三方指令碼。
開發人員工具「效能」面板
依由第三方產品分組
第三方指令碼依產品排序,從最長載入時間開始。

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

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

  1. 使用「網路」面板評估載入網頁所需的時間。
    • 如要模擬實際狀況,建議您開啟網路節流CPU 節流功能。您的使用者不太可能擁有快速的網路連線和桌上型電腦硬體,在研究室情況下,這會造成昂貴的指令碼影響。
  2. 封鎖可能有問題的第三方指令碼網址或網域 (請參閱 Chrome 開發人員工具效能面板,瞭解如何識別高成本指令碼)。
  3. 重新載入網頁,並再次評估載入時間。
    • 為獲得更準確的資料,建議您至少評估三次載入時間。某些第三方指令碼會考量到每次載入網頁時擷取不同的資源。為解決這個問題,開發人員工具效能面板支援多個錄製內容。

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

WebPageTest 支援封鎖未載入個別要求,以評估其影響,方法是依序前往「進階設定」 >「封鎖」。使用這項功能指定要封鎖的網域清單,例如廣告網域。

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

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

  1. 在不封鎖第三方的情況下測試網頁。
  2. 已封鎖部分第三方並重複執行測試。
  3. 從「Test History」中選取兩筆結果。
  4. 按一下 [Compare] (比較)
WebPageTest 顯示比較選項
方便您比較兩份報表
選取要比較的負載測試結果。

下圖顯示 WebPageTest 的幻燈片功能,針對包含及不含有效第三方資源的網頁比較載入順序。建議您針對個別第三方來源進行測試,藉此判斷哪些網域對您的網頁效能影響最大。

WebPageTest 幻燈片顯示
在不使用第三方服務的情況下載入網站所帶來的影響
封鎖第三方資源的影響: Andy Davies 使用 WebPageTest 評估第三方代碼的影響

WebPageTest 也支援在 DNS 層級執行的兩個指令來封鎖網域:

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

WebPageTest 進階設定 > SPOF > 主機無法運作
使用 SPOF 測試功能模擬指定網域故障的情形。

使用長工作偵測昂貴的 iframe

如果第三方 iframe 中的指令碼需要較長的執行時間,可能會封鎖主執行緒並延遲其他工作。這類長時間的工作會導致事件處理常式無法正常運作或影格遺失,因而對使用者體驗造成負面影響。

如要偵測實際使用者監控 (RUM) 的長時間工作,請使用 JavaScript PerformanceObserver API 觀察長期工作項目。這些項目包含歸因屬性,可用於判斷哪個影格結構定義導致長時間工作。

以下程式碼會將 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 查詢和重新導向。您可以使用 資源提示,在頁面載入程序的早期,針對代管第三方指令碼的網域執行 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 變更或安全性修正項目,除非您手動更新指令碼,否則可能會導致收益損失或安全性問題。

或者,您也可以使用服務工作站快取第三方指令碼,進一步控制從網路擷取指令碼的頻率。此外,您也可以使用服務工作處理程序建立載入策略,限制不必要的第三方要求,直到網頁接近關鍵使用者時刻為止。

針對較小的使用者進行 A/B 版本測試

A/B 測試 (或分割測試) 是一種對兩個網頁版本進行實驗的技術,用於分析使用者體驗和行為。它會向不同網站流量樣本提供網頁版本,並根據數據分析判斷哪個版本帶來的轉換率較高。

然而,在設計上,為了判斷哪些實驗需要啟用,A/B 測試會延遲轉譯。JavaScript 通常用於檢查使用者是否屬於 A/B 測試實驗,然後啟用正確的變化版本。即使使用者未參與實驗,這項程序也可能會降低使用者體驗。

為加快網頁轉譯速度,建議您將 A/B 測試指令碼傳送給少數使用者樣本,並執行程式碼來決定在伺服器端顯示哪個網頁版本。

延遲載入第三方資源

如果設計不良,內嵌的第三方資源 (例如廣告和影片) 可能會導致網頁載入速度變慢。只有在必要時才能使用延遲載入功能,例如等待使用者在頁面頁尾放送廣告,直到使用者捲動畫面到畫面上為止。您也可以在主要網頁內容載入後,但在使用者可能與網頁互動之前,延遲載入第三方內容。

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

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

DoubleClick 提供有關如何延遲載入廣告的說明,請參閱官方文件

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

以往,偵測元素是否因為延遲載入而在可視區域中是否可見,這些方法都很容易出錯,且經常拖慢瀏覽器運作速度。這些效率不佳的方法通常會監聽捲動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 以非同步方式部署代碼,這樣就不會阻止彼此載入、降低瀏覽器執行代碼所需的網路呼叫次數,並在資料層使用者介面中收集代碼資料。

使用代碼管理工具的風險

雖然代碼管理工具的設計有助於簡化頁面載入速度,但使用這項工具有助於加快網頁載入速度,原因如下:

  • 如果代碼管理工具中的代碼和自動事件監聽器過多,會使瀏覽器發出超過必要網路要求,因而降低程式碼快速回應事件的能力。
  • 凡是擁有憑證和存取權的使用者,都能在代碼管理工具中加入 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 評論。