IFR 性能数据 v0.5

本页收录支撑首屏直出(IFR)与元素模板的全部测量数据。每轮 campaign 回答一个问题:

campaign它回答的问题
1. 策略阶梯主线程同步渲染每种设计花多少钱——上限在哪里?
2. 全示例扫描IFR 在真实应用上的体积与 TTI 成本是多少、语义是否安全?(顺带证明:单进程测不出它的收益。)
3. 真实线程跨真实线程边界时 IFR 到底赢多少——以 ReactLynx 为对照组。
3b. 大应用复测一旦 TodoMVC / Hacker News / AI Chat / Elk 进入矩阵,−19% 中位是否还站得住?

关于配置命名。第 1、2 轮 campaign 早于 enableIFR 默认联动元素模板的改动。 本页各列已映射为今天的产品配置:原始报告中的 ifr 即今天的 IFR without ET(显式 enableElementTemplates: false),ifr+et 即今天的默认 enableIFR: true。第 3b 轮始终显式设置两个开关。完整方法学与原始数据: 策略基准全示例扫描真实浏览器验证大应用复测

1. 策略阶梯

结论:元素模板是渲染成本的拐点。纯 IFR 重放的 JS 成本与完整渲染相当 (解释器下每千元素约 8–11 ms);ET 砍掉 7–15×;Vapor 式设计还能再买 2–3×、贴到 PAPI 地板。这就是 ET 默认随 IFR 开启的原因:它攻击的正是 IFR 给主线程新增的唯一真实成本——loadTemplate 内的同步首屏渲染。

七种渲染策略被逐一原型化,对同样的逻辑首屏、经同一 Element PAPI 表面测量, 渲染文档逐字节一致。场景约 1000–1400 元素:static-heavy(99.7% 模板 静态)、content(卡片流,37%)、list(v-for,12%)。

Warm 渲染耗时,--jitless V8(解释器 ≈ 主线程引擎代理)

variantstatic-heavycontentlist
bg-baseline(No IFR 管线)11.86 ms9.36 ms6.87 ms
IFR without ET(线上)10.94 ms8.40 ms6.57 ms
ifr-direct(原型)8.17 ms6.36 ms4.89 ms
ifr-static-tpl(原型)1.11 ms5.29 ms4.00 ms
IFR + ET(线上,默认)0.74 ms1.26 ms1.44 ms
ifr-vapor(原型上界)0.53 ms0.55 ms0.46 ms
papi-floor(参照)0.54 ms0.39 ms0.31 ms

Cold 首次执行,--jitless(模拟设备一次性首帧)

variantstatic-heavycontentlist
IFR without ET18.0 ms16.4 ms11.7 ms
IFR + ET4.2 ms5.3 ms4.9 ms
ifr-vapor1.4 ms1.2 ms0.8 ms

需要跨线程传输的 ops 载荷

variantstatic-heavycontentlist
无 ET77.6 KB60.4 KB45.1 KB
有 ET69 B9.2 KB17.1 KB

原型保留作参考:ifr-direct 已被 ET 吸收(模板实例化天然蕴含持句柄直接 应用);Vapor 设计仍是跟踪中的 endgame——其原型省略了 reactive-effect 簿记,数字应读作乐观上界。

2. 全示例扫描

结论:这轮测的是 IFR 的成本语义安全性,不是收益。代价是 bundle gzip ×2.26、TTI 上界 ×1.36;安全性结论是 22/23 个示例在全部配置下渲染出 逐字节一致的文档。逐项 FCP 列是持平的(中位 ×1.04)——这本身就是发现: IFR 是双线程架构优化,单进程 harness 里没有后台启动和 IPC 可供移除。 请把持平的 FCP 读作"JS 工作量守恒"的证据,真正的收益量化见第 3 节。

每个示例以三种配置构建,作为真实 bundle 的两半在 PAPI-over-jsdom 环境中 执行(每项 5 次取中位,--jitless,主线程 parse 剔除,等价于 lepus 字节码 预编译)。

exampleNo IFRIFR w/o ETΔIFR + ETTTI No IFRTTI IFR w/o ETΔTTInodes
7guis65.663.1−4%64.365.676.0+16%169
basic32.034.3+7%33.732.044.0+38%9
css-features43.350.0+15%44.243.363.3+46%51
gallery66.665.0−2%69.566.689.4+34%4
hackernews-css40.035.4−11%38.940.058.8+47%14
hackernews-tailwind55.953.0−5%52.255.976.1+36%20
hello-world33.535.6+6%36.033.545.7+36%16
keep-alive47.744.5−7%46.547.757.0+19%56
main-thread26.724.3−9%24.526.733.0+24%3
networking24.930.5+23%35.124.930.5+23%0
option-api53.857.1+6%59.753.868.8+28%9
pinia40.138.7−4%39.440.150.0+25%19
provide-inject32.234.3+6%37.932.243.7+36%13
reactivity33.636.1+7%36.033.646.1+37%19
slots40.143.8+9%39.040.154.3+35%47
suspense42.338.4−9%38.342.351.1+21%16
swiper30.328.5−6%29.830.341.1+36%47
tailwindcss22.525.8+15%20.922.536.9+64%71
todomvc17.921.6+21%20.717.931.4+76%11
todomvc-day120.420.1−2%15.920.429.4+44%7
transition45.945.2−1%47.745.959.7+30%56
v-model39.140.9+4%40.739.152.3+34%26
vue-router43.245.4+5%45.043.260.3+40%6

(FCP/TTI 单位 ms。networking 首帧 0 节点——fetch 驱动型,即文档标注 "不建议开 IFR"的画像。todomvc-codex 测量时应用代码线程不兼容,之后已在 example 层修复。)

Bundle 体积(gzip,KiB)——最主要的成本

exampleNo IFR开 IFRΔ
hello-world34.576.3+121%
gallery37.280.0+115%
hackernews-css72.6179.1+147%
networking57.5145.5+153%
tailwindcss36.279.0+118%
中位(全示例)×2.26

主线程段从 ~17 KiB(仅 worklet 注册)增长到 78–195 KiB(Vue 运行时 + 应用 副本);ET 在此之上仅增加约 1%。这次扫描还发现并修复了三个真实 bug (SystemInfo 覆写、数字样式烘焙绕过 auto-px 归一化、CSS Modules 令主线程 bundle 崩溃)——单为正确性,把每种真实应用形状过一遍双线程管线也是值得的。

3. 真实线程

结论:有了真实线程边界,IFR 在内容优先屏幕上获胜——按 example 集与宿主, FCP 约 −8% 到 −26%,中位分别为 −19%(十个 demo)与 −12%(后续七应用集)。 收益来源是把后台启动 + IPC 从关键路径移除。小屏上两种 IFR 配置(带/不带 ET)的 web FCP 通常只差几个百分点:ET 更清晰的实测优势仍在渲染成本与 ops 载荷(第 1 节)以及原生冷启动。

环境:Lynx for Web——后台运行时跑在真实 Web Worker 中、真实 postMessage IPC、headless Chromium。FCP = <lynx-view> 插入 → 首次绘制内容,7 个全新 浏览器 context 取中位。下面两档节流出自同一会话,以当前开关语义测量 (enableIFR: true = IFR + ET;显式 opt-out = IFR without ET)。绝对毫秒 数随宿主负载在会话间漂移;组内比值才是稳定的度量。

ReactLynx 对照组

ReactLynx 没有 IFR 关闭开关,用空主线程首屏 + 完整后台渲染忠实模拟"关闭"。 先看与第 2 节相同的单进程 harness:ReactLynx 同样持平——参照实现在 没有线程边界时同样无法展示自己的招牌特性:

ReactLynx 探针(单进程,jitless)FCPTTI
IFR 开25.3 ms32.7 ms
IFR 关(模拟)24.3 ms24.3 ms

真实线程下两个框架都赢,且是同一量级:ReactLynx 探针(85 节点)从 97.7 ms 降到 75.2 ms(−23%),正落在下方 Vue examples 的区间内。

完整矩阵——无 CPU 节流

example(节点数)No IFRIFR w/o ETΔIFR + ET(默认)Δ
hello-world(16)96.675.8−22%75.4−22%
todomvc-day1(7)92.978.6−15%73.4−21%
swiper(39)100.577.7−23%79.1−21%
tailwindcss(68)95.780.9−15%80.6−16%
keep-alive(49)103.586.0−17%84.4−18%
transition(55)104.693.3−11%85.1−19%
7guis(145)104.190.3−13%80.6−23%
gallery(302)136.6104.5−23%109.9−20%
css-features(50)102.093.9−8%100.3−2%
hackernews-css(18)115.3131.7+14%131.8+14%

(FCP 单位 ms。中位:默认配置 −19%,不带 ET −15%——两种配置的逐项 差异会在不同运行间翻转,应读作噪声。此处 Hacker News 行早于 shell IFR, 见 §3b。)

4× CPU 节流

exampleNo IFRIFR w/o ETΔIFR + ETΔ
hello-world344.1282.8−18%289.1−16%
todomvc-day1313.2281.7−10%280.6−10%
swiper333.1304.9−8%298.4−10%
tailwindcss339.9330.7−3%316.4−7%
keep-alive391.4366.6−6%370.8−5%
gallery(302 节点)437.2430.5−2%434.5−1%
css-features352.0353.6+0%346.4−2%
transition350.6355.2+1%367.6+5%
7guis352.1366.8+4%355.0+1%
hackernews-css324.0352.9+9%360.0+11%
ReactLynx 探针331.6308.0−7%

本轮的两个读法:

  1. 内容优先的屏幕在节流下保住收益(hello-world −16…−18%、todomvc-day1 −10%、swiper −10%),而 FCP 由 CSS 处理或大 bundle 主导的屏幕压缩到 接近零——节流的 CPU 放大了 web 平台付在 FCP 路径上的 bundle 解析项。
  2. 反转画像在两档节流都可能复现——当首屏几乎没有同步 chrome 时。上表 Hacker News 行在整段跳过 IFR mount 时满速 +14%、节流 +9…11%;改为 shell IFR(始终 mount、挡住 fetch)后,满速约 −12%——见 §3b。原生 预编译 lepus 字节码会把构成反转的解析项压小。

距离单线程裸 Web 有多远?

单线程原生基线(plain Vue 用 @vue/runtime-dom;plain Preact 用 ReactLynx 同款 fork 指回真实 DOM)把剩余差距拆开。以 ReactLynx 探针屏、无节流为例:

组成成本证据
渲染 85 个元素 + 绘制(preact on DOM)~21 msplain-preact,框架预解析
+ 框架拉取+解析落在 FCP 路径+7 mscold − warm
+ Lynx-for-Web 平台层+47 msrl-ifr − plain-preact cold
+ 后台启动 + hydration IPC 往返+23 msrl-noifr − rl-ifr

线程边界的成本约 23 ms,IFR 移除的正是这一片。与裸 Web 的剩余差距是 web 宿主的仿真层——每个宿主自己的常数项;原生 Lynx 的平台层是原生代码, 不付这笔。

3b. 大应用复测

结论:小内容优先屏仍按第 3 节理解;产品级应用加入后,把中位读成区间。 第二轮 Lynx for Web(显式 off / et / ifr / ifr-et;hello-world、 TodoMVC、gallery、Hacker News、AI Chat、Elk)满速内容优先中位约 −12% ——仍落在第 3 节 −8%…−26% 的逐项带内,但低于 −19% 的套件中位。4× 节流下 Elk / AI Chat 约 +25% 到 +44%,七应用中位略偏正。gzip 仍约 ×2.2–2.5(此处中位 ×2.23,相对第 2 节 ×2.26)。

来源集合IFR + ET 相对 No IFR 的 FCP(无节流)备注
第 3 轮(Claude Code)10 个偏小 example−8% 到 −23%,中位 −19%ReactLynx 对照 −23%
第 3b 轮(Cursor)7 应用含 TodoMVC / gallery / HN / AI Chat / Elk内容优先 ~−12%(hello −26%);七应用中位 −12%(HN 已 shell IFR)另一宿主,绝对 ms 更低;比比值
第 3b @ 4× 节流同上内容优先 ~−6%;七应用中位 ~+3%Elk +44%,AI Chat +25%

跨 §3 与 §3b:把 −12% 到 −19% 当作 Lynx for Web 上合理的内容优先中位带, 而不是单一的 −19% 标题。ET-only 体积约免费(~+1%)、web FCP 接近持平; ET 默认随 IFR 开启,依据仍是策略阶梯的渲染成本(复测约 6–15×), 不是小屏 web FCP。

原始 JSON 与写评: packages/ifr-bench/reeval/

4. 原生引擎观察

全示例套件已在原生模拟器(LynxExplorer,Lynx SDK 1.4 / PrimJS)上验证: 24/25 通过、0 次 hydration mismatch,No IFR 与 IFR+ET 视觉一致(SSIM ≥ 0.9977;scoped CSS、烘焙 inline style 与 auto-px 语义在原生引擎全部正确)。 单次冷启动录屏显示 IFR 首帧内容提前约 0.3 s(gallery)到约 1.2 s(7guis) ——是机制方向的确认,不作为稳定 benchmark。

复现

# 策略阶梯 + 正确性 oracle
pnpm --filter vue-lynx-ifr-bench run check
pnpm --filter vue-lynx-ifr-bench run bench

# 全示例扫描
node packages/ifr-bench/examples-sweep/orchestrate.mjs <dir>
node packages/ifr-bench/examples-sweep/sweep.mjs <dir>

# 真实浏览器(Lynx for Web)测量,含 plain-web 基线
node packages/ifr-bench/web-harness/run-browser.mjs <bundlesDir> [runs] [throttle]

# §3b 用的四配置聚焦重建(含 ai-chat / elk)
node packages/ifr-bench/reeval/orchestrate-focused.mjs <dir>