本案例研究描述了 Trendyol 如何通过利用 Google 工具(如 PageSpeed Insights (PSI)、Chrome DevTools 和 scheduler.yield
API)调试和改进 React 中 INP 的逐步工作流程。
任何电子商务网站的两个关键组成部分是商品列表页 (PLP) 和商品详情页 (PDP)。电子商务流量通常来自商品列表页,无论是通过电子邮件营销活动、社交媒体还是广告。因此,至关重要的是要确保 PLP 体验经过精心设计,以缩短完成购买所需的时间。优先考虑用户体验质量对于取得成功至关重要。《Milliseconds Make Millions》(《毫秒造就百万美元》)等研究出版物已经揭示了 Web 性能对消费者在线消费意愿和品牌互动意愿的重大影响。
Trendyol 是一个电子商务平台,拥有约 3000 万客户和 24 万卖家,这使我们成为土耳其第一家估值超过 100 亿美元的企业,也是全球顶级的电子商务平台之一。
为了实现大规模提供最佳用户体验的目标,同时保持内容的灵活性并使用旧版本的 React,Trendyol 专注于将“交互到下次绘制”(INP) 作为改进的关键指标。本案例研究描述了 Trendyol 改进其 PLP 上 INP 的历程,最终使 INP 降低了 50%,搜索结果业务指标提升了 1%。
Trendyol 的 INP 调查流程
INP 衡量网站对用户输入的响应速度。“良好”的 INP 表明浏览器能够快速可靠地响应所有用户输入并重绘页面,这是良好用户体验的关键组成部分。
Trendyol 改进其 PLP 上 INP 的历程始于在进行任何改进之前对用户体验进行全面分析。根据 PSI 报告,PLP 的真实用户体验在移动设备上的 INP 为 963 毫秒,如下图所示。

为了确保良好的响应速度,网站所有者应力争将 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
操作成本很高,这可能会给低端设备带来问题,因为它会长时间占用主线程。
开发人员用来将任务分解为更小任务的一种方法是使用 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 得到了改善,因为主要的长任务已被分解为一系列较小的任务,这使得更高优先级的工作(例如用户交互和后续渲染工作)能够比原本更快地发生。

请注意,Trendyol 使用 PuzzleJs 框架来实现使用 React v16.9.0 的微前端架构。使用 React 18 也可以实现相同的性能,但由于多种原因,Trendyol 目前无法升级。
业务成果
为了衡量实施 INP 改进的影响,我们进行了 A/B 测试,以查看业务指标如何受到影响。总体而言,我们对 PLP 的更改带来了显着的改进,包括 INP 降低了 50%,以及每个用户会话从列表页到商品详情页的点击率提升了 1%。在下图中,您可以看到 INP 如何随时间推移在 PLP 上得到改善

结论
优化 INP 是一个复杂且迭代的过程,但通过清晰的工作流程可以使其更容易。调试和改进网站 INP 的简单方法取决于您是否正在收集自己的字段数据。如果您没有收集,PSI 和 Lighthouse 是一个好的起点。一旦您确定了有问题页面,您可以使用 DevTools 深入挖掘以尝试重现问题。
不时地让步于主线程,让浏览器有更多机会执行紧急工作,这将使您的网站更具响应性,确保您的客户获得更好的用户体验。较新的调度 API(如 scheduler.yield()
)使此任务更容易。
特别感谢 Google 的 Jeremy Wagner、Barry Pollard 和 Houssein Djirdeh,以及 Trendyol 工程团队对这项工作的贡献。