發布日期:2021 年 7 月 29 日
代碼是插入網站的第三方程式碼片段,通常會透過代碼管理工具插入。代碼最常用於行銷和數據分析。
代碼和代碼管理工具對網站效能的影響程度差異很大。代碼管理工具可視為信封:代碼管理工具提供容器,但您要填入什麼內容,以及如何使用,則取決於您。
本文將說明如何針對成效和 Core Web Vitals 最佳化代碼和代碼管理工具。雖然本文參照 Google 代碼管理工具,但許多討論的概念也適用於其他代碼管理工具。
對 Core Web Vitals 的影響
代碼管理工具通常會消耗網頁載入速度和回應速度所需的資源,進而間接影響 Core Web Vitals。頻寬可用於下載網站的代碼管理工具 JavaScript,或此工具後續的呼叫。主要執行緒的 CPU 時間可用於評估及執行代管器和代碼中包含的 JavaScript。
在重要網頁載入時間期間,Largest Contentful Paint (LCP) 容易發生頻寬爭用情形。此外,封鎖主執行緒可能會延遲 LCP 轉譯時間。
累計版面配置轉移 (CLS) 可能會受到影響,原因可能是在首次轉譯前延遲載入重要資源,或是標記管理工具將內容插入網頁。
與下一個顯示的內容 (INP) 互動容易受到主執行緒的 CPU 爭用問題,且我們發現代碼管理工具的大小與 INP 分數偏低。
選擇合適的代碼類型
廣告代碼對成效的影響會因廣告代碼類型而異。一般來說,圖片代碼 (「像素」) 的效能最高,其次是自訂範本,最後是自訂 HTML 代碼。供應商代碼會因允許的功能而異。
請注意,標記的使用方式會對成效產生極大影響。「像素」在很大程度上非常出色,因為這種標記類型的性質對使用方式設有嚴格限制。自訂 HTML 標記並不會一直降低效能,但由於使用者享有的自由程度,因此容易遭到濫用,而且使用方式造成效能不佳。
在考量代碼時,請留意規模:單一代碼的成效影響可能微乎其微,但如果同一個網頁使用數十或數百個代碼,成效影響就可能相當顯著。
並非所有程式輔助函式都應透過代碼管理工具載入
代碼管理工具通常不是載入資源的最佳方式,因為這類資源會實作使用者體驗的即時視覺或功能面向,例如 Cookie 通知、主圖片或網站功能。使用代碼管理工具載入這些資源通常會延遲傳送。這樣不但會對使用者體驗造成負面影響,而且可能導致 LCP 和 CLS 等指標增加。
此外,有些使用者也會封鎖代碼管理工具。如果使用代碼管理工具導入使用者體驗功能,可能會導致部分使用者的網站無法正常運作。
使用自訂 HTML 標記時請小心
自訂 HTML 標記已存在多年,且在大多數網站上廣泛使用。您可以使用自訂 HTML 代碼輸入自己的程式碼,且限制較少,因為這個代碼的主要用途是將自訂 <script>
元素新增至網頁,而非如其名稱所示。
自訂 HTML 標記的用途多元,成效影響也大不相同。評估網站效能時,請注意,大多數工具會將自訂 HTML 代碼的效能影響歸因於插入代碼的代碼管理工具,而非代碼本身。
自訂 HTML 代碼可將元素插入周圍網頁。在網頁中插入元素的動作可能會導致效能問題,在某些情況下也會造成版面配置變動。
- 在大多數情況下,如果元素插入頁面,瀏覽器就必須重新計算頁面上每個項目的大小和位置。這項程序稱為「版面配置」。單一版面的效能影響程度不大,但如果過度使用,就可能導致效能問題。這種現象對低階裝置和含有大量 DOM 元素的網頁影響較大。
- 如果在周圍區域已轉譯完成後,將可見的網頁元素插入 DOM,可能會導致版面配置位移。這種現象並非標記管理工具獨有,但由於標記通常會比網頁的其他部分晚載入,因此通常會在周圍網頁已轉譯後才插入 DOM。
使用自訂範本
自訂範本支援與自訂 HTML 標記相同的部分作業,但是以沙箱版 JavaScript 建構而成,可提供API,用於指令碼插入和像素插入等常見用途。顧名思義,這類範本可由進階使用者建立,他們可以考量效能來建構範本。較少技術人員可使用範本。這種做法通常比提供完整的自訂 HTML 存取更安全。
由於自訂範本受到更多限制,因此這些代碼不太可能出現效能或安全性問題。基於相同原因,自訂範本無法適用於所有用途。
正確插入指令碼
使用代碼管理工具插入指令碼是相當常見的用途。建議您使用自訂範本和 injectScript
API。
如要瞭解如何使用 injectScript API 轉換現有的自訂 HTML 代碼,請參閱「轉換現有代碼」一文。
如果您必須使用自訂 HTML 標記,請注意以下事項:
- 程式庫和大型第三方指令碼應使用可下載外部檔案的指令碼標記 (例如
<script src="external-scripts.js">
) 載入,而不是直接將指令碼的內容複製貼到標記中。雖然不使用<script>
標記可避免單獨的來回連線,以便下載指令碼的內容,但這項做法會增加容器大小,並防止瀏覽器單獨快取指令碼。 - 許多供應商建議將
<script>
標記放在<head>
的頂端。不過,如果是透過代碼管理工具載入的指令碼,通常就不需要這麼做。在大多數情況下,在代碼管理工具執行時,瀏覽器已完成剖析<head>
。
使用像素
有時,第三方指令碼可以替換成圖片或 iframe 像素。與以指令碼為基礎的對應項目相比,像素可能支援的功能較少,因此通常不太受歡迎。不過,如果在代碼管理工具中使用像素,則像素的動態性會更高,因為像素可以根據觸發條件觸發並傳遞不同的變數。
像素是效能最高且最安全的代碼類型,因為在觸發後不會執行 JavaScript。像素的資源大小非常小 (小於 1 KB),而且不會導致版面配置位移。
請洽詢第三方供應商,進一步瞭解他們支援的像素。此外,您也可以嘗試檢查程式碼是否有 <noscript>
標記。如果供應商支援像素,通常會在 <noscript>
標記中加入像素。
像素的替代方案
像素廣告的主要原因是,在伺服器回應不相關的情況下 (例如傳送資料給數據分析供應商),像素廣告是當時最便宜且最可靠的 HTTP 要求方式之一。navigator.sendBeacon()
和 fetch() keepalive
API 的設計目的是因應相同用途,但可說比 Pixel 更可靠。
繼續使用像素並無不妥,因為像素受到良好支援,且對效能影響不大。不過,如果您打算自行建構信標,建議您考慮使用其中一種 API。
sendBeacon()
navigator.sendBeacon()
API 設計用於在伺服器回應不重要時,將少量資料傳送至網路伺服器。
const url = "https://example.com/analytics";
const data = JSON.stringify({
event: "checkout",
time: performance.now()
});
navigator.sendBeacon(url, data);
sendBeacon()
的 API 功能有限:只支援提出 POST 要求,不支援設定自訂標頭。適用於所有新版瀏覽器支援。
Fetch API keepalive
keepalive
是一種旗標,可讓您使用 Fetch API 提出事件報表和分析等非阻斷式要求。這項設定是在傳遞至 fetch()
的參數中加入 keepalive: true
。
const url = "https://example.com/analytics";
const data = JSON.stringify({
event: "checkout",
time: performance.now()
});
fetch(url, {
method: 'POST',
body: data,
keepalive: true
});
如果 fetch() keepalive
和 sendBeacon()
看起來很相似,那是因為它們確實相似。事實上,在 Chromium 瀏覽器中,sendBeacon()
現在是以 fetch()
keepalive
為基礎建構而成。
在選擇 fetch() keepalive
和 sendBeacon()
時,請務必考量所需的功能和瀏覽器支援情形。fetch() API 的彈性更高,但 keepalive
的瀏覽器支援比 sendBeacon()
少。
瞭解標記的作用
代碼通常會按照第三方供應商提供的指引建立。如果不清楚廠商的程式碼的作用,建議您向相關人員洽詢。取得第二意見有助於判斷代碼是否可能造成效能或安全性問題。
建議您在代碼管理工具中加上擁有者標籤。你很容易忘記標記擁有者,而且不會因為有內容破壞時而害怕拆除!
觸發條件
整體而言,最佳化代碼觸發條件通常包括確保不會超過必要觸發代碼,以及選擇在業務需求和效能成本之間取得平衡的觸發條件。
觸發條件是 JavaScript 程式碼,可提高代碼管理工具的大小和執行成本。雖然大部分的觸發事件都很小,但累積起來的影響可能會相當可觀。舉例來說,如果有許多點擊事件或計時器觸發條件,代碼管理工具的工作負載可能會大幅增加。
選擇適當的觸發事件
代碼對效能造成的影響可能有所不同。一般來說,代碼觸發的時間越早,對效能造成的影響就越大。資源通常會在初始頁面載入期間受到限制,因此載入或執行特定資源 (或標記) 會將資源從其他位置移除。
雖然請務必為所有標記選擇適當的觸發條件,但對於可載入大型資源或執行較長指令碼的標記來說,格外重要。
代碼可在網頁瀏覽 (通常為 Page load
、on DOM Ready
、on Window Loaded
) 或自訂事件觸發。為避免影響網頁載入,請在 Window Loaded
後觸發非必要的代碼。
使用自訂事件
使用自訂事件觸發條件,回應 Google 代碼管理工具內建觸發條件未涵蓋的網頁事件。舉例來說,許多代碼都會使用網頁瀏覽觸發事件。但是,DOM Ready
和 Window Loaded
之間的時間可能很長,因此標記觸發時很難微調。自訂事件可以解決這個問題。
首先,請建立自訂事件觸發條件,並更新代碼以使用這個觸發條件。
如要觸發觸發條件,請將對應事件推送至資料層。
// Custom event trigger that fires after 2 seconds
setTimeout(() => {
dataLayer.push({
'event' : 'my-custom-event'
});
}, 2000);
使用特定的觸發條件
定義特定觸發條件,避免在不需要時觸發代碼。其中一種最簡單且有效的方法,就是確保代碼只在實際使用的網頁上觸發。
內建變數可納入觸發條件中,藉此限制代碼觸發時機。
在適當時間載入代碼管理工具
您可以調整代碼管理工具的載入時機,藉此改善成效。無論觸發條件如何設定,都必須在代碼管理工具載入後才能觸發。請嘗試調整載入代碼管理工具的時機,因為這可能會產生相同或更大的影響。這項決定會影響網頁上的所有代碼。
將代碼管理工具的載入作業延後,可避免不小心過早載入代碼,進而避免日後發生效能問題。
變數
使用變數讀取網頁中的資料。這類變數可用於觸發條件和代碼本身。
與觸發條件一樣,變數會在代碼管理工具中加入 JavaScript 程式碼,因此可能會導致效能問題。變數可以相對較小,例如用於讀取網址、Cookie、資料層或 DOM 部分的程式碼。也可以包含無限制功能 (和大小) 的自訂 JavaScript。
請盡量減少變數用量,因為代碼管理工具會持續評估變數。移除不再使用的舊變數,以縮減代碼管理工具指令碼的大小和處理時間。
標記管理
有效使用標記可降低成效問題的風險。
使用資料層
資料層是 JavaScript 物件陣列,其中包含網頁相關資訊。這些物件包含您要傳遞至 Google 代碼管理工具的所有資訊。
資料層也可用於觸發代碼。
// Contents of the data layer
window.dataLayer = [{
'pageCategory': 'signup',
'visitorType': 'high-value'
}];
// Pushing a variable to the data layer
window.dataLayer.push({'variable_name': 'variable_value'});
// Pushing an event to the data layer
window.dataLayer.push({'event': 'event_name'});
雖然 Google 代碼管理工具不必搭配資料層使用,但我們強烈建議您使用資料層。資料層會將第三方指令碼可存取的資料整合到單一位置,進而提供更清晰的使用情形。這有助於減少不必要的變數計算和指令碼執行作業。
使用資料層,您就能控管代碼存取哪些資料,而非提供完整的 JavaScript 變數或 DOM 存取權。
由於更新資料層會導致 Google 代碼管理工具重新評估所有容器變數,並可能觸發代碼 (這會導致 JavaScript 執行),因此資料層的成效優勢可能不明顯。雖然資料層可能會遭到濫用,但一般來說,如果資料層似乎是效能問題的來源,容器本身可能會有效能問題。資料層會讓這些問題更加明顯。
移除重複和未使用的代碼
除了透過代碼管理工具插入代碼,如果網頁的 HTML 標記中也包含代碼,就可能出現重複的代碼。
您應暫停或移除未使用的代碼,而不是透過觸發條件例外狀況封鎖。暫停或移除標記會從容器中移除程式碼,但封鎖不會。
移除未使用的代碼後,請檢查觸發條件和變數,判斷是否也能移除這些項目。
已暫停的代碼會影響容器大小,但總酬載量會比代碼處於啟用狀態時來得小。
使用允許和拒絕清單
使用允許和拒絕清單,針對網頁上允許的代碼、觸發條件和變數,設定精細的限制。這有助於強制執行效能最佳做法和其他政策。
允許和拒絕清單會透過資料層設定。
window.dataLayer = [{
'gtm.allowlist': ['<id>', '<id>', ...],
'gtm.blocklist': ['customScripts']
}];
舉例來說,您可以禁止使用自訂 HTML 標記、JavaScript 變數或直接存取 DOM。這意味著,只有像素和預先定義的標記,才能搭配資料層的資料使用。雖然這項做法較為嚴格,但可實現更高效且安全的代碼管理工具導入方式。
考慮使用伺服器端代碼
建議您考慮改用伺服器端代碼,尤其是想進一步掌控資料的大型網站。伺服器端代碼會從用戶端移除供應商程式碼,並透過該代碼將處理程序從用戶端卸載至伺服器。
舉例來說,使用用戶端代碼時,如果要將資料傳送至多個 Analytics 帳戶,就必須讓用戶端針對每個端點發出個別要求。使用伺服器端代碼時,用戶端會向伺服器端容器提出單一要求,而這項資料會從該容器轉送至不同的 Analytics 帳戶。
請注意,伺服器端代碼僅適用於部分代碼。廣告代碼相容性會因供應商而異。
詳情請參閱「伺服器端代碼簡介」一文。
容器
代碼管理工具通常會在設定內允許多個執行個體 (通常稱為「容器」)。您可以在一個代碼管理工具帳戶中控制多個容器。
每個網頁僅使用一個容器
單一頁面上的多個容器可能會造成重大效能問題,因為這會引入額外的額外負擔和指令碼執行作業。至少,它會複製核心標記程式碼本身,而這類程式碼會作為容器的 JavaScript 的一部分提供,因此無法在容器之間重複使用。
多個容器很少能有效使用。不過,如果控制得宜,這麼做還是有用。例如:
- 包括更淺的「提前載入」容器,以及更大型的「後續載入」容器,而非單一大型容器。
- 使用受限的容器,適合較不技術的使用者,並受到限制更嚴格的容器限制,以便執行較複雜的標記。
如果每個網頁都需要使用多個容器,請按照 Google 代碼管理工具指南來設定多個容器。
視需要使用不同的容器
如果您將代碼管理工具用於多個資源 (例如網頁應用程式和行動應用程式),使用的容器數量可能會影響工作流程的生產力。也會影響成效。
如果網站的用途和結構相似,單一容器就能有效地用於多個網站。舉例來說,雖然品牌的行動和網頁應用程式可能提供類似的功能,但應用程式的結構可能不同,因此透過個別容器管理會更有效率。
過度重複使用單一容器可能會強制要求複雜的邏輯來管理代碼和觸發條件,進而增加容器的複雜性和大小。
留意容器大小
容器的大小取決於代碼、觸發條件和變數。雖然小型容器仍可能對網頁效能造成負面影響,但大型容器幾乎肯定會造成影響。
最佳化代碼使用方式時,「容器大小」不應是最重要的指標。不過,容器大小過大通常是警訊,表示容器維護不當,且可能遭到濫用。
Google Tag Manager 會將容器大小限制為 300 KB,並在容器大小達到大小限制的 70% 時發出警告。
大多數網站應盡量將容器大小控制在限制以下。為方便比較,網站容器的中位數約為 50 KB。經過壓縮後,Google 代碼管理工具的程式庫大小約為 33 KB。
為容器版本命名
容器版本是容器內容在特定時間點的快照。使用有意義的名稱,並附上簡短說明內含的重要變更,有助於日後更輕鬆地偵錯成效問題。
標記工作流程
請務必管理代碼變更,避免對網頁成效造成負面影響。
部署前先測試
請在部署之前測試代碼,在傳送前找出問題和效能等等。
測試代碼時,請考量下列事項:
- 代碼是否正常運作?
- 這個標記是否會導致版面配置位移?
- 代碼是否載入任何資源?這些資源有多大?
- 標記是否會觸發長時間執行的指令碼?
預覽模式
預覽模式可讓您在實際網站上測試代碼變更,而不需先將變更部署至公開版本。預覽模式包含偵錯控制台,可提供代碼相關資訊。
在預覽模式下執行時,Google Tag Manager 的執行時間會有所不同 (稍微變慢),因為需要額外的額外負擔,才能在偵錯主控台中顯示資訊。因此,我們不建議比較在預覽模式和正式環境中收集的 Web Vitals 評量資料。不過,這項差異不應影響標記本身的執行行為。
獨立測試
另一種測試代碼的方法,是設定空白網頁,其中包含一個容器,並在其中放入要測試的單一代碼。這項測試設定較不切實際,也無法找出一些問題 (例如標記是否造成版面配置位移),但能讓您更容易隔離及評估標記對指令碼執行等事項的影響。瞭解 Telegraph 如何運用這種隔離方式提升第三方程式碼的效能。
監控代碼成效
Google 代碼管理工具 Monitoring API 可用來收集特定代碼執行時間的相關資訊。此資訊會回報給您選擇的端點。
詳情請參閱「如何建立 Google 代碼管理工具監控工具」。
需要核准容器變更
第一方程式碼通常會在部署前經過審查和測試。對待標記的方式相同。
新增兩步驟驗證功能,要求管理員核准容器變更,就是其中一種做法。或者,如果您不想要求使用者進行兩步驟驗證,但仍想密切留意變更,可以設定容器通知,以便收到您選擇的容器事件電子郵件快訊。
定期稽核標記使用情形
使用標記時,其中一個難題是標記往往會隨著時間累積:標記會新增,但很少會移除。定期稽核標記是扭轉這種趨勢的一種方法。理想的頻率取決於網站代碼更新的頻率。
標示每個標籤,讓擁有者一目瞭然,方便識別誰負責該標籤,並能指出是否仍需要該標籤。
稽核代碼時,請務必清理觸發條件和變數。這類問題也經常會導致效能問題。
詳情請參閱「控管第三方指令碼」。