Trendyol 指出 INP 減少 50% 的方式,使點閱率提升 1%

本案例研究說明瞭如何利用 Google 工具 (例如 PageSpeed Insights (PSI)Chrome 開發人員工具scheduler.yield API),逐步完成偵錯及改善 Trendyol 在 React 中使用的 INP 的流程。

任何電子商務網站都包含兩個重要元素:產品資訊頁面 (PLP) 和產品詳細資料頁面 (PDP)。電子商務流量通常來自產品資訊頁面,無論是透過電子郵件廣告活動、社群媒體或廣告。因此,務必確保 PLP 體驗經過精心設計,以縮短購買所需的時間。優先考量使用者體驗品質,是成功的關鍵。Milliseconds Make Millions 等研究報告已揭露網頁效能對消費者願意在線上消費和與品牌互動的影響。

Trendyol 是一家電子商務平台,擁有約 3,000 萬名顧客和 24 萬名賣家,這也讓我們成為土耳其第一家估值超過 100 億美元的企業,也是全球最受歡迎的電子商務平台之一。

為了達成目標,即在大量提供最佳使用者體驗的同時,維持內容的彈性並與舊版 React 搭配運作,Trendyol 將 Interaction to Next Paint (INP) 視為可改善的重要指標。本個案研究說明 Trendyol 改善 PLP 的 INP 歷程,結果INP 降低 50% 搜尋結果業務指標提升 1%

Trendyol 的 INP 調查程序

INP 可評估網站回應使用者輸入內容的速度。良好的 INP 表示瀏覽器能夠快速且可靠地回應所有使用者輸入內容,並重新繪製網頁,這也是良好使用者體驗的關鍵要素。

Trendyol 改善 PLP 的 INP 之路,首先是徹底分析使用者體驗,然後再進行改善。根據 PSI 報告,PLP 的實際使用者體驗 INP 為 963 毫秒 (如下圖所示)。

根據 PageSpeed Insights 的 CrUX 讀數,Trendyol 的 INP 截至 2023 年 9 月 5 日,Trendyol 的 INP 為 963 毫秒,屬於「差」的範圍。
Trendyol 的 INP,截至 2023 年 9 月 5 日,由 PSI 提供。

為了確保良好的回應速度,網站擁有者應力求 INP 低於或等於 200 毫秒,也就是說,Trendyol 的 INP 在當時屬於「差」的範圍。

幸好,PSI 提供的現場資料,包含 Chrome 使用者體驗報告 (CrUX) 中網頁的資料,以及詳細的實驗室診斷資料。查看實驗室資料後,Lighthouse 的 JavaScript 執行時間稽核顯示,search-result-v2 指令碼占用主執行緒的時間比頁面上的其他指令碼還要長。

針對 Trendyol 網站,在 Lighthouse 中顯示長時間工作階段的來源。長時間工作任務的主要來源,是用於處理 Trendyol PLP 搜尋結果的指令碼。
截至 2023 年 9 月 5 日,Trendyol 的 JavaScript 執行時間稽核結果 (來自 PSI)。

為了找出實際的瓶頸,我們使用 Chrome 開發人員工具中的效能面板排解 PLP 體驗問題,並找出問題來源。在 Chrome 開發人員工具中模擬 CPU 速度降低 4 倍的行動裝置效能,顯示在主執行緒上有 700 到 900 毫秒的長時間工作。如果主執行緒因其他工作而占用時間超過 50 毫秒,可能無法及時回應使用者輸入內容,導致使用者體驗不佳。

在 Chrome 開發人員工具中,針對 Trendyol 的 PLP 進行效能分析時的螢幕截圖。這項長時間執行的工作會執行 737.6 毫秒,並屬於 Intersection Observer 回呼的一部分。
Chrome 開發人員工具效能面板中,Trendyol 的 PLP 上長時間工作負載的效能分析器。

最長的任務是由 Intersection Observer API 回呼所造成,該回呼會在 React 元件內的搜尋結果指令碼上執行。此時,我們開始著手將長時間工作拆分為小型區塊,讓瀏覽器有更多機會回應優先順序較高的工作,包括使用者互動。

結果發現,使用 setState 運算 (會在 Intersection Observer 回呼中觸發 React 重新繪製) 的成本過高,可能會佔用主執行緒太久,對低階裝置造成問題。

開發人員用來將工作細分為較小工作的方法之一,是使用 setTimeout。我們使用這項技巧,將 setState 呼叫的執行作業延後至另一個工作。雖然 setTimeout 可延後 JavaScript 執行作業,但不會提供任何優先順序控制項。因此,我們加入了scheduler.yield 來源試用版,以確保在讓出主執行緒後,指令碼執行作業能繼續進行:

/*
* Yielding method using scheduler.yield, falling back to setTimeout:
*/
async function yieldToMain() {
  if('scheduler' in window && 'yield' in scheduler) {
    return await scheduler.yield();
  }

  return new Promise(resolve => {
    setTimeout(resolve, 0);
  });
}

/*
* Yielding to the main thread before changing the state of the component:
*/
const observer = new IntersectionObserver((entries) => {
  entries.forEach(handleIntersection);
  const maxNumberOfEntries = Math.max(...this.intersectingEntries);

  if (Number.isFinite(maxNumberOfEntries)) {
    await this.yieldToMain();

    this.setState({ count: maxNumberOfEntries });
  }
}, { threshold: 0.5 });

將這個產生方法加入 PLP 程式碼後,INP 便會有所改善,因為主要的長時間工作已分割為一系列較短的工作,讓優先順序較高的作業 (例如使用者互動和後續轉譯作業) 提早執行。

在 Chrome 開發人員工具中,針對 Trendyol 的 PLP 進行效能分析時的螢幕截圖。先前執行時間為 737.6 毫秒的長時間工作,現在已分割成數個較小的工作。
將工作分割成較小的部分。

請注意,Trendyol 使用 PuzzleJs 架構,以 React 16.9.0 版本實作微前端架構。使用 React 18 可以達到相同的效能,但基於多項原因,Trendyol 目前無法升級。

業務成果

為了評估導入的 INP 改善功能所帶來的影響,我們進行了 A/B 版本測試,瞭解對業務指標的影響。整體而言,我們對 PLP 的變更帶來顯著改善,包括 INP 減少 50%,以及每個使用者工作階段從產品資訊頁面到產品詳細資料頁面的點閱率提升 1%。下圖顯示 INP 如何隨著時間推移改善 PLP:

六個月內 Trendyol 的 INP 第 75 百分位數螢幕截圖。在六個月結束時,Trendyol 的 INP 從近 1,400 毫秒降至近 650 毫秒。
第 75 個百分位數 INP 改善情形隨時間變化。

結論

改善 INP 是一個複雜且需要反覆進行的過程,但只要有明確的工作流程,就能簡化這項作業。您是否收集自己的實地資料,決定了如何簡單地偵錯及改善網站的 INP。如果您還沒有,PSI 和 Lighthouse 就是不錯的起點。找出有問題的網頁後,您可以使用開發人員工具深入探討,嘗試重現問題。

不時交出主執行緒,讓瀏覽器有更多機會執行緊急工作,這樣網站的回應速度就會更快,確保客戶享有更優質的使用者體驗。較新的排程 API (例如 scheduler.yield()) 可讓這項工作更輕鬆。

特別感謝 Google 的 Jeremy Wagner、Barry Pollard 和 Houssein Djirdeh,以及 Trendyol 的工程團隊,感謝他們對這項工作的貢獻。