如何運用 Long Animation Frames API (LoAF) 並採用實用的收益策略,協助 Taboola 為發布商改善網站回應速度,而不減損廣告成效。
「與下一個顯示的內容互動 (INP)」指標可評估網站在使用者輸入內容的回應速度。INP 會評估使用者開始互動 (例如點選、輕觸或輸入) 後,產生視覺回饋的時間。INP 即將在 2024 年 3 月取代 First Input Delay (FID) 做為 Core Web Vitals。
Taboola 是全球首屈一指的內容探索平台,在開放網路中每秒提供 500,000 個推薦項目。這些最佳化建議讓 Taboola 有 9,000 家專屬發布商合作夥伴,協助他們透過目標對象營利及互動。發布商使用 JavaScript 在網頁上顯示推薦內容。
第三方 JavaScript 會影響網頁快速回應使用者輸入內容的能力,因此 Taboola 投入大量心力來縮減 JavaScript 檔案大小和執行時間。Taboola 已重新設計整個算繪引擎,也會在不採用抽象機制的情況下直接使用瀏覽器 API,盡可能降低對 INP 的影響。
本個案研究涵蓋 Taboola 透過全新長動畫影格 (LoAF) API,評估其對實際網頁回應度的影響,藉此改善 INP 的改善歷程,以及後續調整具體做法以改善使用者體驗。
TBT 做為 INP 的 Proxy
總封鎖時間 (TBT) 是一項研究室指標,可找出主執行緒在哪個位置遭到封鎖,進而影響網頁回應速度。測量回應速度 (例如 INP) 的實際指標可能會受到高 TB 影響。Annie Sullivan 對行動裝置的 TBT 與 INP 之間關聯性的調查結果顯示,在盡量減少主執行緒封鎖時間的情況下,網站更有可能達成良好的 INP 分數。
這樣的關聯,同時也與 Taboola 發布者Toola 是非常關注高未定案的疑慮,因此 Taboola 著重於將對這項指標的貢獻降到最低。
Taboola 採用 TBT 做為 INP 的 Proxy 指標,開始監控及最佳化 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 來源試用,試圖進一步瞭解對使用者輸入回應回應的實際影響。來源試用提供全新或實驗功能的存取權,可讓開發人員測試新興功能,而且可讓使用者限時試用。
這裡一定要強調的是,最困難的部分是,在不犧牲任何廣告 KPI(主要成效指標) 或造成發布商資源延遲的情況下,成功改善 INP。
使用 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 });
- 使用
loafEntryAnalysis
函式,可讓 Taboola 找出主要貢獻者的項目。 - 如果 Taboola 最長的指令碼時間長度超過半數是 Taboola,或者 Taboola 指令碼執行時間超過 50 毫秒,系統就會視為主要貢獻者。
- 如果使用者互動因長動畫影格而延遲,就會產生
firstUIEventTimeStamp
。系統會將最長封鎖時間長度視為整體 INP 分數,也可以識別 Taboola 何時觸發firstUIEventTimeStamp
,以便計算 Taboola INP 分數。
透過 LoAF 收集資料後,Taboola 建立了下列歸因表,以便找出可運用收益商機的區域。
TRECS Engine:全新收益策略
除了使用 LoAF 深入瞭解指令碼的最佳化做法,Taboola 也已重新設計整個算繪引擎,大幅減少 JavaScript 的執行和封鎖時間。
TRECS (Taboola Recommendations 可擴充客戶服務) 會維持用戶端轉譯作業和發布商目前的 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 更能瞭解對 INP 的影響。這項工具也特別標出可用於新 TRECS 引擎的指令碼最佳化商機。
為了判斷 TRECS 和 Performance Fader 的影響,Taboola 針對現有引擎進行 A/B 版本測試,評估 INP 的成效,且沒有針對多個發布商合作夥伴的樣本產生指令碼。
下表是 Taboola 聯播網中四個匿名發布商的第 75 個百分位數,以毫秒為單位的 INP 結果。
幸好,在測試面板啟用 TRECS 和 Performance Fader 的情況下,廣告點閱率和每 1,000 次曝光 (千次曝光收益) 等業務指標不受影響。隨著 INP 的正向改善,但 Google Ads KPI 未達到預期任何負面結果,Taboola 將逐步改善發布商的對產品的觀感。
我們先前針對同一客戶執行另一個 Lighthouse 結果顯示,採用新引擎時 Taboola 大幅改善主執行緒的封鎖時間。
由此可見,使用 LoAF 找出使用 INP 的成因,並透過 Performance Fader 部署後續的收益技術,讓 Taboola 的合作夥伴在廣告和網頁成效中均能獲得最大成效。
結論
最佳化 INP 的程序相當複雜,尤其在合作夥伴網站上使用第三方指令碼時更是如此。在進行最佳化之前,將 INP 歸因於特定指令碼後,即可免除任何憑空猜測,以及對其他網站成效指標造成的潛在損害。LoAF API 是我們識別 INP 的一項重要工具,可找出並解決內嵌第三方的特定 INP 問題,同時免除網頁上其他技術的干擾。
搭配良好的收益策略 (例如使用 scheduler.postTask()
) 使用時,LoAF 可協助您觀察並瞭解網頁回應速度不佳的原因,進而取得改善網站 INP 所需的資訊。
在此特別感謝 Google 的 Gilberto Cocchi、Noam Rosenthal 和 Rick Viscomi 和 Taboola 工程與產品團隊的 Dedi Hakak、Anat Dagan 和 Omri Ariav 對此專案的貢獻。