瞭解 Taboola 如何運用 Long Animation Frames API (LoAF),並採用智慧型讓步策略,在不影響廣告成效的情況下,提升發布商網站的回應速度。
Interaction to Next Paint (INP) 指標可評估網站對使用者輸入內容的回應速度。INP 會評估使用者開始互動 (例如點選、輕觸或輸入) 到產生視覺回饋所需的時間。INP 預計於 2024 年 3 月取代 First Input Delay (FID),成為 Core Web Vitals。
Taboola 是全球首屈一指的內容探索平台,每秒在開放網路上提供 50 萬則推薦內容。這些最佳化建議可協助 Taboola 的 9,000 個專屬發布商合作夥伴營利,並吸引目標對象。發布者會使用 JavaScript 在網頁上顯示建議。
由於第三方 JavaScript 可能會影響網頁快速回應使用者輸入內容的能力,Taboola 大幅投入資源,縮減 JavaScript 檔案大小和執行時間。Taboola 重新設計了整個算繪引擎,並直接使用瀏覽器 API (不含抽象化),盡可能減少對 INP 的影響。
本案例研究涵蓋 Taboola 的歷程,說明該公司如何使用新的 Long Animation Frames (LoAF) API 評估對網頁回應速度的影響,並採取後續措施,套用特定最佳化設定來提升使用者體驗,進而改善 INP。
以 TBT 做為 INP 的替代指標
總封鎖時間 (TBT) 是以實驗室為基礎的指標,可找出主執行緒遭封鎖的時間長度,可能影響網頁回應速度。如果 TBT 偏高,可能會影響用來評估回應性的現場指標,例如 INP。Annie Sullivan 對行動裝置上 TBT 與 INP 之間關聯性的研究指出,如果網站盡量縮短主執行緒封鎖時間,就越有可能獲得良好的 INP 分數。
這種關聯性加上 Taboola 發布商對高 TBT 的疑慮,促使 Taboola 專注於盡量減少對這項指標的影響。
RELEASE.js 等指令碼會封鎖主要執行緒 691 毫秒。
Taboola 開始使用 TBT 做為 INP 的替代指標,監控並最佳化 JavaScript 執行時間,以限制其對 Core Web Vitals 的潛在影響。他們首先採取了下列行動:
- 使用 Long Tasks API 找出並最佳化實際環境中造成問題的指令碼。
- 每天使用 PageSpeed Insights API 評估 10,000 到 15,000 個網址,預估 TBT 貢獻度。
不過,Taboola 發現使用這些工具分析 TBT 有一些限制:
- Long Tasks API 無法將工作歸因於來源網域或特定指令碼,因此更難找出長時間工作的原因。
- Long Tasks API 只會找出長時間執行的工作,不會找出可能導致延遲算繪的工作和版面配置變更組合。
為解決這些挑戰,Taboola 參與了 Long Animation Frames (LoAF) API 原始碼試用活動,進一步瞭解這項 API 對使用者輸入回應速度的實際影響。來源試用可讓開發人員使用新功能或實驗功能,測試新興功能,使用者則可在一段時間內試用這些功能。
請務必注意,這項挑戰最困難的部分,在於如何成功改善 INP,同時不影響任何 Google Ads KPI(主要成效指標),也不會導致發布商的資源延遲。
使用 LoAF 評估 INP 影響
如果延遲超過 50 毫秒才更新算繪,就會發生動畫影格過長的情況。Taboola 找出使用者介面更新緩慢的原因 (而不只是長時間執行的工作),進而分析這對實際環境中網頁回應速度的影響。觀察 LoAF 後,Taboola 能夠:
- 將屬性項目指派給特定 Taboola 工作。
- 在將特定功能部署至正式環境前,先觀察效能問題。
- 收集匯總資料,在 A/B 測試中比較不同程式碼版本,並回報主要成效指標。
以下 JavaScript 是簡化版,用於實際運作環境中收集 LoAF,以區隔 Taboola 的影響。
function loafEntryAnalysis (entry) {
if (entry.blockingDuration === 0) {
return;
}
let taboolaIsMajor = false;
const hasInteraction = entry.firstUIEventTimestamp > 0;
let taboolaDuration = 0;
const nonTaboolaLoafReport = {};
const taboolaLoafReport = {};
entry.scripts.forEach((script) => {
const taboolaScriptBlockingDuration = handleLongAnimationFrameScript(script, taboolaLoafReport, nonTaboolaLoafReport);
taboolaDuration += taboolaScriptBlockingDuration;
if (taboolaScriptBlockingDuration > 0 || taboolaDuration > entry.duration / 2) {
taboolaIsMajor = true;
}
});
generateToboolaLoafReport(taboolaLoafReport, nonTaboolaLoafReport, hasInteraction, taboolaIsMajor);
if (hasInteraction) {
const global = _longAnimationFramesReport.global;
global.inpBlockingDuration = Math.max(global.inpBlockingDuration, entry.blockingDuration);
if (taboolaIsMajor) {
global.taboolaInpBlockingDuration = Math.max(global.taboolaInpBlockingDuration, entry.blockingDuration);
}
}
}
const observer = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
loafEntryAnalysis(entry);
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
- Taboola 透過
loafEntryAnalysis函式,找出自己是主要貢獻者的項目。 - 如果 Taboola 導致的總指令碼時間超過一半,或 Taboola 指令碼的執行時間超過 50 毫秒,系統就會將 Taboola 視為主要影響因素。
- 如果使用者互動因動畫影格過長而延遲,系統就會產生
firstUIEventTimeStamp。系統會將最長的封鎖時間視為整體 INP 分數。我們也可以判斷 Taboola 何時觸發firstUIEventTimeStamp,以計算 Taboola INP 分數。
Taboola 運用 LoAF 收集的資料建立下列歸因表格,找出可套用收益機會的領域。
TRECS 引擎:全新的收益策略
除了使用 LoAF 更瞭解指令碼最佳化機會,Taboola 也重新設計了整個轉譯引擎,大幅縮短 JavaScript 執行和封鎖時間。
TRECS (Taboola Recommendations Extensible Client Service) 可維護用戶端算繪和發布商目前的 JS 程式碼,同時減少載入 Taboola 建議所需的必要檔案數量和大小。
使用 LoAF 找出會阻斷算繪的工作後,「Performance Fader」可以先中斷這些工作,再使用 scheduler.postTask() 讓出主執行緒。這項設計可確保無論主執行緒是否正在執行其他工作,系統都會盡快執行重要的使用者面向工作,例如算繪更新。
以下是「Performance Fader」工作執行器的 JS 程式碼片段:
/**
* Send a task to run using the Fader. The task will run using the browser Scheduler, by the configuration settings, or immediately.
* @param task
* @param isBlocker
*/
function sendTaskToFader (task, isBlocker = true) {
const publisherFaderChoice = fillOptimizationGlobals(); // Loading publisher choice
const applyYielding = publisherFaderChoice === OptimizationFaderType.Responsiveness;
if (applyYielding) {
return runAsPostTask(task, isBlocker);
}
return runImmediately(task);
}
/**
* Yielding method using scheduler.postTask and falling back to setTimeout when it's not availabe based on the publisher choice
*/
function runAsPostTask (task, isBlocker = true) {
if ('scheduler' in window && 'postTask' in scheduler) {
const priority = isBlocker ? 'user-blocking': 'background';
return window?.scheduler?.postTask(task, { priority });
}
const publisherChoiceEnableFallback = fillPublisherChoices();
if (publisherChoiceEnableFallback) {
return new Promise(resolve => {
window.setTimeout(() => {
resolve(task());
}, 0);
});
}
return runImmediately(task);
}
sendTaskToFader 函式的作用如下:
- 使用
runAsPostTask,後者會使用scheduler.postTask()(如果 API 可用),或改用setTimeout。 - 這個函式會將函式呼叫包裝在程式碼區段中,導致動畫影格時間過長和 INP。這項功能會將這些程式碼區段分割為較短的工作,進而縮短 INP。
業務指標
Taboola 運用 LoAF 更深入瞭解自身對 INP 的影響,這項工具也列出可做為新 TRECS 引擎一部分的指令碼最佳化商機。
為判斷 TRECS 和 Performance Fader 的影響,Taboola 對一組發布商合作夥伴進行 A/B 測試,並根據現有引擎 (面板上沒有產生指令碼) 評估 INP。
下表顯示 Taboola 聯播網中四位匿名發布商的第 75 百分位數 INP 結果 (以毫秒為單位)。
所幸,在測試面板上啟用 TRECS 和成效衰減功能後,廣告點閱率和每千次曝光收益 (RPM) 等業務指標並未受到負面影響。INP 沒有任何負面結果,且廣告 KPI 表現良好,因此 Taboola 將逐步改善發布商對產品的觀感。
稍早對同一位客戶執行的另一次 Lighthouse 測試顯示,使用新引擎後,Taboola 的主執行緒封鎖時間大幅縮短。
RELEASE.js 等指令碼將 TBT 減少 485 毫秒 (-70%)。
這項結果顯示,使用 LoAF 找出 INP 的原因,並透過 Performance Fader 部署後續的產生技術,有助於 Taboola 合作夥伴在廣告和網頁成效方面獲得最大成功。
結論
最佳化 INP 是複雜的程序,尤其是在合作夥伴網站上使用第三方指令碼時。開始最佳化之前,將 INP 歸因於特定指令碼可避免任何臆測,並防止其他網站效能指標受到影響。LoAF API 已證明是識別及解決 INP 問題的實用工具,特別是針對嵌入的第三方,可讓他們找出具體的 SDK 改進機會,同時排除網頁上其他技術的干擾。
搭配良好的產生策略 (例如使用 scheduler.postTask()) 時,LoAF 可協助您觀察及瞭解網頁回應速度緩慢的原因,進而取得改善網站 INP 的必要資訊。
特別感謝 Google 的 Gilberto Cocchi、Noam Rosenthal 和 Rick Viscomi,以及 Taboola 工程和產品團隊的 Dedi Hakak、Anat Dagan 和 Omri Ariav,他們對這項工作貢獻良多。