このケーススタディでは、PageSpeed Insights(PSI)、Chrome DevTools、scheduler.yield
API などの Google ツールを活用して、Trendyol で使用されている React の INP のデバッグと改善を行うワークフローを段階的に説明します。
あらゆる e コマース ウェブサイトの重要なコンポーネントとして、商品リスティング ページ(PLP)と商品詳細ページ(PDP)があります。e コマースのトラフィックは、メール キャンペーン、ソーシャル メディア、広告などを通じて、商品リスティング ページから発生することがよくあります。そのため、購入にかかる時間を短縮できるように、PLP エクスペリエンスが慎重に設計されていることが重要です。成功を収めるには、ユーザー エクスペリエンスの質を優先することが不可欠です。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 で CPU の遅延を 4 倍にしてモバイル パフォーマンスをエミュレートしたところ、メインスレッドで 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 の変更により、INP が 50% 減少し、ユーザー セッションあたりのリスティング ページから商品の詳細ページへのクリックスルー率が 1% 向上するなど、大幅な改善が見られました。次の図は、PLP での INP が時間の経過とともにどのように改善されたかを示しています。
まとめ
INP の最適化は複雑で反復的なプロセスですが、明確なワークフローがあれば簡単に行うことができます。ウェブサイトの INP をデバッグして改善するための簡単な方法は、独自のフィールドデータを収集しているかどうかによって異なります。まだ使用していない場合は、PSI と Lighthouse から始めることをおすすめします。問題のあるページを特定したら、DevTools を使用して詳細を調べ、問題を再現してみます。
メインスレッドに時折譲歩して、ブラウザが緊急作業を行う機会を増やすと、ウェブサイトの応答性が向上し、ユーザー エクスペリエンスが向上します。scheduler.yield()
などの新しいスケジューリング API を使用すると、このタスクが簡単になります。
この作業に貢献してくれた Google の Jeremy Wagner、Barry Pollard、Houssein Djirdeh 氏、Trendyol のエンジニアリング チームに感謝します。