このケーススタディでは、Trendyol が PageSpeed Insights(PSI)、Chrome DevTools、scheduler.yield
API などの Google ツールを活用して、React で INP のデバッグと改善を行う詳細なワークフローについて説明します。
あらゆる e コマース ウェブサイトの重要なコンポーネントとして、商品リスティング ページ(PLP)と商品詳細ページ(PDP)があります。e コマースのトラフィックは、多くの場合、メール キャンペーン、ソーシャル メディア、広告など、商品リスティング ページから発生します。そのため、購入までの時間を短縮するには、PLP エクスペリエンスを慎重に設計することが重要です。成功を収めるには、ユーザー エクスペリエンスの質を優先することが不可欠です。Milliseconds Make Millions(Milliseconds Make Millions)などの研究発表では、消費者の購買意欲やオンラインでのブランド エンゲージメントに対するウェブ パフォーマンスの影響が大きいことが明らかになっています。
Trendyol は、約 3,000 万人の顧客と 24 万の販売者を抱える e コマース プラットフォームです。評価額 100 億ドルを超えるトルコ初の企業となり、世界トップクラスの e コマース プラットフォームの一つとなっています。
コンテンツの柔軟性を維持しながら、古いバージョンの React と連携しながら、可能な限り最高のユーザー エクスペリエンスを大規模に提供するという目標を達成するために、Trendyol は改善の重要な指標として Interaction to Next Paint(INP) を重視しました。このケーススタディでは、Trendyol が PLP の INP を改善し、INP が 50% 削減され、検索結果のビジネス指標が 1% 向上した取り組みについて説明します。
Trendyol の INP 調査プロセス
INP は、ユーザー入力に対するウェブサイトの応答性を測定します。優れた INP は、ブラウザがすべてのユーザー入力にすばやく確実に応答し、ページを再描画できることを示します。これは優れたユーザー エクスペリエンスの重要な要素です。
Trendyol が PLP で INP を改善する取り組みは、改善を行う前にユーザー エクスペリエンスを徹底的に分析することから始まりました。PSI レポートによると、PLP の実際のユーザー エクスペリエンスでは、次の図に示すように、モバイルで 963 ミリ秒の INP でした。
優れた応答性を実現するには、サイト所有者は INP を 200 ミリ秒未満に抑える必要があります。つまり、当時の Trendyol の INP は「低い」範囲にありました。
幸い、PSI には、Chrome ユーザー エクスペリエンス レポート(CrUX)に含まれるページのフィールド データと、詳細なラボ診断データの両方が用意されています。ラボデータから、Lighthouse の JavaScript 実行時間の監査で、search-result-v2
スクリプトがページ上の他のスクリプトよりも長い時間メインスレッドを占有していることが示唆されました。
実際のボトルネックを特定するため、Chrome DevTools のパフォーマンス パネルを使用して PLP のエクスペリエンスのトラブルシューティングを行い、問題の原因を特定しました。Chrome DevTools で 4 倍の CPU 速度を下げたモバイル パフォーマンスをエミュレートしたところ、メインスレッドで 700 ~ 900 ミリ秒のタスクが発生しました。メインスレッドが他のタスクで50 ミリ秒以上占有されている場合、ユーザー入力にタイムリーに応答できず、ユーザー エクスペリエンスが低下する可能性があります。
最も長いタスクは、React コンポーネント内の検索結果スクリプトに対する Intersection Observer API コールバックによって発生しました。そこで、長いタスクを小さなチャンクに分割し、ブラウザが優先度の高い作業(ユーザー操作など)に応答する機会を増やすことを検討し始めました。
Intersection Observer コールバック内で React の再レンダリングをトリガーする setState
オペレーションを使用すると、コストが高くなることが判明しました。これは、メインスレッドを長時間占有するため、低価格デバイスで問題になる可能性があります。
デベロッパーがタスクを小さなものに分割するために使用していた方法の 1 つに、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 });
この yielding メソッドを PLP コードに追加することで、主な長いタスクが小さなタスクに分割され、ユーザー操作やその後のレンダリング作業などの優先度の高い作業をより早く行うことができるため、INP が改善されました。
Trendyol は、PuzzleJs フレームワークを使用して、React v16.9.0 を使用したマイクロフロントエンド アーキテクチャを実装しています。React 18 では同じパフォーマンスを達成できますが、Trendyol は現時点ではさまざまな理由でアップグレードできません。
ビジネス上の成果
実装された INP 改善の影響を測定するため、A/B テストを実施してビジネス指標への影響を調べました。PLP の変更により、全体的には大幅に改善されました。たとえば、ユーザー セッションごとにリスティング ページから商品の詳細ページへのクリック率が 1% 上昇し、INP が 50% 減少しました。次の図では、INP の経時的な PLP の改善を示します。
まとめ
INP の最適化は複雑で反復的なプロセスですが、明確なワークフローがあれば簡単に行えます。ウェブサイトの INP をデバッグして改善するための簡単な方法は、独自のフィールドデータを収集しているかどうかによって異なります。まだ使用していない場合は、PSI と Lighthouse から始めることをおすすめします。問題のあるページを特定したら、DevTools を使用して詳細を調べ、問題の再現を試みます。
メインスレッドに時折譲歩して、ブラウザが緊急の処理を行う機会を増やすと、ウェブサイトの応答性が向上し、ユーザー エクスペリエンスが向上します。scheduler.yield()
などの新しいスケジューリング API を使用すると、このタスクが簡単になります。
この作業に貢献してくれた Google の Jeremy Wagner、Barry Pollard、Houssein Djirdeh 氏、Trendyol のエンジニアリング チームに感謝します。