搬运与补充自《蒋宏伟-58RN页面秒开方案与实践》—2021全球大前端技术大会小册子

(似乎是内部资料了,网上搜不到买不到)

image.png

目录


性能优化的业务收益

做性能优化,耗时是降低了,但对业务来说有什么收益呢?

以 首屏时间 和 访问流失率 的关系,发现:

性能 好 的页面再优化,实际收益比预期 差 ;

性能 差 的页面优化,实际收益比预期 好 。

这就是 性能优化收益的分化。

于是作者设计了几个指标,来驱动业务进行性能优化。

  1. 流失率
  2. 首屏时间
  3. 秒开收益 —如果页面实现了秒开,流失率会降低多少

首屏时间的采集指标

一个页面的加载流程有5个阶段:

  1. 用户进入
  2. 首次内容绘制FCP
  3. 业务组件渲染完成 Biz Update
  4. 最大内容绘制 LCP
  5. 可视区加载完成

这其中,2~4都可以作为首屏指标。那怎么去比较呢?

指标 理由1:非侵入式/自动采集? 理由2:W3C标准? 为什么 LCP 更好(作为首屏指标)
LCP 🌟 ✅ 是(浏览器自动计算) ✅ 是(Core Web Vitals 核心成员) 它衡量“主角登场”,最接近用户感知的“加载完成”。
FCP ✅ 是(浏览器自动计算) ✅ 是(W3C标准) 它只衡量“加载开始”(可能只是个loading),不代表有意义的内容。
FMP ❌ 否(计算复杂且易错) ❌ 否(已被废弃) LCP 是 FMP 的标准化、非侵入式替代品。
biz_update ❌ 否(需要开发者手动埋点) ❌ 否(公司自定义指标) 侵入式采集,且不具备通用性。
可视区加载完成 ❌ 否(需要重度侵入式脚本轮询) ❌ 否(自定义指标) 侵入式采集,且难以准确定义和实现。

W3C标准:

整个行业公认的、统一的度量衡 。

统一性与互操作性 (Consistency)

  • 一旦成为标准,所有浏览器(Chrome, Firefox, Safari,Edge)都会 用完全相同的方法去实现和计算它 。
  • 这意味着你在 Chrome 上测到的 LCP 和在 Firefox 上测到的 LCP是可以 公平对比 的(苹果-苹果对比)。
  • 而像 FMP 或 biz_update这样的非标准指标,在不同工具里的计算方法五花八门,你无法进行横向对比(苹果-橘子对比)。

稳定性与权威性 (Stability)

  • 标准是经过 W3C 成员(包括谷歌、苹果、微软、Mozilla等所有巨头)的专家们反复讨论、审查和验证过的,确保了它的 准确性 和 稳定性 。
  • 它不会像 FMP那样,因为“不好用”或“不准确”而被官方 废弃(Deprecated) 。公司可以放心地围绕它构建长期的性能监控体系。

强大的生态系统 (Ecosystem)

  • 因为它是标准,所有的 第三方工具 都会跟进支持。
  • 谷歌 (Google) :把它作为 Core Web Vitals(核心网页指标) 之一,直接影响你的 网站 SEO排名 。这是最直接的商业价值
  • 监控工具 :DataDog, New Relic, Sentry等所有性能监控平台都会原生支持 LCP。
  • 开发工具 :Lighthouse, Chrome DevTools都会把它放在最显眼的位置。

侵入/非侵入式采集

“ 侵入式采集 ” (IntrusiveMonitoring),也常被称为“ 有侵入性的监控 ”,它指的是:

采集性能指标的这个行为本身,就已经对页面的性能产生了(通常是负面的)显著影响。

换句话说,用来测量的工具(监控脚本)自己太重、太慢,导致你测量的对象(你的网页)也变慢了。这就违背了性能优化的初衷。

为什么LCP/FCP可以由 浏览器自动计算 ,别的不行?

这触及到了两者最根本的区别:

LCP 和 FCP衡量的是 浏览器的『渲染过程』 ,这是浏览器自己的 本职工作 。

而 biz_update 和“可视区加载完成”衡量的是 『业务逻辑』 ,浏览器对此一无所知。

可以把浏览器想象成一个“厨师”,它在厨房(渲染引擎)里做菜(渲染页面)。

  • FCP (首次内容绘制) :厨师(浏览器) 自己 当然知道自己是什么时候把 第一片菜叶 (第一个像素/logo)放到盘子(屏幕)上的。它只需要在那个时刻“抬手看一眼表”,这个时间就是FCP。
  • LCP (最大内容绘制) :厨师(浏览器)在往盘子里放菜时, 自己 当然也知道哪一块是“最大的主菜”(最大的图片或文本块)。它只需要在把这块主菜放上盘子的那一刻“再看一眼表”,这个时间就是LCP。

这一切都是浏览器 渲染引擎内部 的本职工作。它在绘制每个元素时,完全清楚这个元素是什么、有多大、在什么位置。所以它可以 自动地、非侵入地 计算出这些指标。

biz_update(业务指标)

  • 你(开发者)告诉浏览器:“当我的 商品价格 显示出来时,才算完成”。
  • 浏览器很困惑:“我怎么知道哪一串数字是‘价格’?我只看到一堆<div> 和 <span>。
  • 浏览器无法理解你的“业务逻辑” 。它不知道哪个元素对你的业务是“最重要的”。
  • 因此,你 必须 在你的代码里(比如从API拿到价格并渲染后), 手动 告诉浏览器,这个“手动通知”的动作就是 侵入式埋点 (performance.mark('biz_update'))。

“可视区加载完成”(定义太模糊)

  • 你(开发者)说:“等所有东西都加载完再告诉我。”
  • 浏览器又会困惑:“什么是‘所有东西’?你背景里那个1x1的 追踪像素 算吗?你页脚那个 不重要的图标字体 算吗?你页面上的 广告脚本 算吗?如果有个 轮播图 每5秒加载一张新图,那算不算‘永远加载不完’?”
  • “加载完成”是一个非常模糊且不稳定的概念。正因为它太难定义,W3C才 放弃 了它,转而选择了 LCP作为一个 更稳定、更具代表性 的替代方案。LCP不追求“全部完成”,它只追求“ 主角登场 ”。

所以,最终选定为LCP。


RN中的FCP采集

但是,LCP是web的标准,RN中没有实现。该怎么去采集呢?

image.png

  1. Native线程,记录用户进入时的Start时间戳
  2. Native线程,将Start时间戳注入到JS Context中
  3. JS线程,监听页面中渲染元素的布局事件
  4. JS线程,在页面渲染过程中计算,不断更新LCP值
  5. JS线程,计算得到End时间戳,并上报最终的LCP

最终的LCP = startTime - endTime

难点是怎么 收敛LCP ,即如何判断可视区完全加载?采用的规则是, 所有元素都加载完成,且底部的元素也加载完成时。

怎判定 是否加载完成?

元素的调用周期,是 先调用render,再调用layout。只调用了render的元素,是没有加载完成的元素;只有两者都调用完成了 ,才是加载完成。


原文存档:Notion 原文