如何運用 Long Animation Frames API (LoAF) 和採用智慧收益策略,讓 Taboola 在不損及廣告成效的情況下,改善發布商網站的回應速度。
與下一個顯示的內容互動 (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 評估該 API 對網頁回應速度的影響,進而改善 INP,並在後續努力中應用特定最佳化方式,以改善使用者體驗。
以 TBT 做為 INP 的代理
總封鎖時間 (TBT) 是實驗室測試指標,可找出主執行緒封鎖的時間是否足夠長,可能會影響網頁回應速度。測量回應度的欄位指標 (例如 INP) 可能會受到高 TBT 的影響。Annie Sullivan 針對行動裝置上的 TBT 和 INP 之間的關聯性進行調查,結果顯示,如果將主執行緒的封鎖時間降到最低,網站更有可能獲得良好的 INP 分數。
由於這兩者之間存在相關性,再加上 Taboola 的發布商對高 TBT 感到擔憂,因此 Taboola 將重心放在盡量減少對這項指標的貢獻。
![螢幕截圖:Lighthouse 稽核主執行緒時間遭到阻斷。主執行緒遭到多個指令碼封鎖,總共 2,630 毫秒,其中第三方 JavaScript 占用 712 毫秒。Taboola 的 RELEASE.js 指令碼是造成大部分第三方封鎖時間 (691 毫秒) 的元兇。](https://web.dev/static/case-studies/taboola-inp/image/fig-1.png?authuser=2&hl=zh-tw)
RELEASE.js
等指令碼會阻斷主要執行緒 691 毫秒。使用 TBT 做為 INP 的代理指標,Tabloa 開始監控及最佳化 JavaScript 執行時間,以限制 JavaScript 對 Core Web Vitals 的潛在影響。他們首先採取了以下行動:
- 使用 Long Tasks API,找出並改善欄位中的有問題指令碼。
- 使用 PageSpeed Insights API 評估每天 10,000 到 15,000 個網址,估算 TBT 貢獻。
不過,Taboa 發現使用這些工具分析 TBT 時,有以下限制:
- Long Tasks API 無法將任務歸因於來源網域或特定指令碼,因此更難找出長時間執行的任務來源。
- Long Tasks API 只會識別長時間任務,而非可能導致算繪延遲的任務和版面配置變更組合。
為解決這些問題,Taboa 加入了Long Animation Frames (LoAF) API 原始試用計畫,以便進一步瞭解這項技術對使用者輸入回應的實際影響。來源試用可讓開發人員測試新功能或實驗功能,讓使用者在限時內試用。
請務必強調,這項挑戰最困難的部分,就是如何成功改善 INP,同時不影響任何廣告 KPI(主要成效指標),或造成發布商資源延遲。
使用 LoAF 評估 INP 影響
如果算繪更新延遲超過 50 毫秒,就會出現長動畫影格。Taboola 找出使用者介面更新速度緩慢的原因 (而非單純的長時間工作),進而分析這項問題對實際網頁回應速度的影響。觀察 LoAF 後,Taboa 可以:
- 將項目歸因於特定 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 });
- 使用
loafEntryAnalysis
函式後,Taboa 就能找出自己是主要貢獻者的項目。 - 如果腳本總時間的一半以上是由 Taboola 造成,或是 Taboola 腳本執行時間超過 50 毫秒,就會視為 Taboola 是主要影響因素。
- 如果使用者互動因長動畫影格而延遲,系統就會產生
firstUIEventTimeStamp
。最長的阻斷時間會視為整體 INP 分數。我們也可以判斷 Taboola 何時觸發firstUIEventTimeStamp
,以便計算 Taboola INP 分數。
透過 LoAF 收集的資料有助於 Taboola 建立下列歸因表,找出可應用產生商機的區域。
TRECS Engine:新的收益策略
除了使用 LoAF 進一步瞭解指令碼最佳化機會,Tabloa 也重新設計整個轉譯引擎,大幅縮短 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。
業務指標
多虧 LoAF,Taboola 才能更深入瞭解 LoAF 對 INP 的影響。這項工具也會標示出可用於新 TRECS 引擎的腳本最佳化機會。
為了評估 TRECS 和成效淡出功能的影響,Taboa 在出版商合作夥伴的面板上,針對 INP 與現有引擎 (不含無效指令碼) 進行 A/B 測試。
下表顯示 Taboola 網路中四個匿名發布商的 INP 結果,以毫秒為單位,並以第 75 百分位數為準。
所幸,在測試面板中啟用 TRECS 和成效淡出功能後,廣告點閱率和每千次曝光收益 (RPM) 等業務指標並未受到負面影響。在 INP 方面取得正面進展後,廣告 KPI 沒有任何負面影響,Tabloa 將逐步改善發布商對產品的看法。
另一個 Lighthouse 在先前提到的客戶上執行時,顯示 Taboola 使用新引擎時,主執行緒阻斷時間大幅改善。
![在套用新的 TRECS 和 Performance Fader 引擎後,Lighthouse 稽核檢查畫面截圖,顯示封鎖主執行緒的時間。審查時間縮短至僅 206 毫秒,而最佳化前為 712 毫秒。](https://web.dev/static/case-studies/taboola-inp/image/fig-2.png?authuser=2&hl=zh-tw)
RELEASE.js
等指令碼將 TBT 縮短 485 毫秒 (-70%)。
這項研究顯示,使用 LoAF 找出 INP 的原因,並透過成效淡出器部署後續的收益技術,可讓 Taboola 合作夥伴在廣告和網頁成效方面獲得最佳成效。
結論
改善 INP 是一項複雜的程序,尤其是在合作夥伴網站上使用第三方指令碼時。在開始進行最佳化前,將 INP 歸因於特定指令碼,可避免您對其他網站效能指標的猜測,並避免造成潛在的損害。LoAF API 已證實是用來找出及解決 INP 問題的實用工具,特別是針對嵌入的第三方,因為這可讓他們找出特定 SDK 改善機會,同時消除網頁上其他技術的干擾。
搭配使用 LoAF 和良好的產生策略 (例如使用 scheduler.postTask()
),就能觀察並瞭解網頁回應速度不佳的原因,進而提供改善網站 INP 所需的資訊。
特別感謝 Google 的 Gilberto Cocchi、Noam Rosenthal 和 Rick Viscomi,以及 Taboola 工程和產品團隊的 Dedi Hakak、Anat Dagan 和 Omri Ariav,感謝他們對這項工作的貢獻。