perf(core): [MOD-03] complete hot-path measurement and compatibility acceptance

This commit is contained in:
Harvey Zhao committed 2026-09-14 16:23:37 +08:00
1 parent 48a7f1ecb0
commit b1e0b976b0
11 files changed
+17732 -11

No files matched your search

+9
View File
@@ -95,6 +95,15 @@ fields. Raw reads return unknown, including historically accepted JSON primitive
this is not schema validation. Read errors use settings by reference, write errors
update that fallback, and successful native reads do not merge it. Changing that
failure policy requires an explicit compatibility decision rather than a type cast.
Successful native reads return independently parsed objects, including nested
records; they must not become a shared mutable cache. Playback recording reads
the times member, then Storage.set reads the latest complete envelope before
merging. A custom public get can change unrelated settings between those calls.
Any future reduction of reads must preserve both independent results and those
interleaved settings. `test/browser/storage-performance.spec.js` checks these
behaviors against published and installed candidates using native localStorage,
and records separate uninstrumented synthetic-event timings and operation counts.
It does not prove atomicity across concurrent browser processes.
utils/dom.ts is a compatibility export surface. dom/tree.ts owns node/query/class
operations; dom/styles.ts owns native style conversion; dom/event-path.ts owns
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,76 @@
# MOD-03 核心热路径测量与选择性优化
本任务完成计划中的核心测量与优化工作。生产改动在检查点
`23a4f22b7256392ddb4cc6b2eef5bed6e93879d2`,本次补齐持久化、当前构造采样、布局
读写和实际安装包的正式配对验收。没有把性能工作定义成所有计时必须单向变快,
也没有把体积审查信号或未来候选复盘自动关闭。
## 按原任务范围核对
| 范围 | 实际工作与证据 |
| --- | --- |
| 进度更新 | 共享slider只写变化的ARIA值,保留实时读取及外部DOM恢复;main/legacy各三引擎三组旧新配对,100次重复刷新从500次写入降为0;见slider-updates-validation.json |
| DOM读写 | 当前安装包验证原生ResizeObserver构造同步控件高度读取0次、fallback1次;40项设置首次导航1次查询/41次样式读取,无关按键0/0,动态隐藏/禁用/恢复的焦点继续正确;12项原生检查通过 |
| 持久化 | 原生Storage/JSON操作与独立计时、旧新三组/三引擎共9项检查;验证正常读取返回独立对象、写回保留中途加入的其他设置、暂停后不保存;保留既有实现 |
| 初始化与销毁 | 当前源码10次热身/60次实际首帧、构造与销毁的Chromium采样;再用实际安装包完成三引擎各三组BASE-06正式旧新配对,54次候选资源探针通过 |
| 兼容和类型 | 新隔离包36项运行时入口检查、5组旧类型模式、8组精确类型模式均通过;原2859项单元及main/legacy交互回归见前检查点,播放器源码此后未改 |
| 体积与无效/拒绝方案 | 保存原始计时、变慢组、初版测试错误、原349ms失败;不靠缓存可变存储对象、删第二次读取、延迟清理或改阈值获得更好数字 |
## 持久化的实际成本与取舍
每个旧新变体先实际播放,预热100次合成timeupdate,然后记录五组各100次刷新,
计时期间不替换Storage/JSON方法。另一个100事件窗口才包装原生方法计数:两边均
为200次getItem、200次JSON.parse、100次JSON.stringify和100次setItem。
每100事件的三组中位数:Chromium旧约1.4–1.6ms、新1.5–1.8ms;Firefox旧2ms、
新1–2ms;WebKit旧1–2ms、新3ms。保留原始样本及计时精度限制;这是整个合成
timeupdate链路,不是单独Storage耗时,不从中推算真实视频每秒的开销或宣称改进。
直接复用解析对象会改变正常get的对象隔离;直接重用第一次envelope可能覆盖自定义
get在两次读取之间写入的其他设置。原生旧版/候选均验证了这两条行为,因此本轮
没有为减少读写而改变存储格式、写入频率、保留规则或同步API。被拒绝方案来自
代码审查与契约验证,不声称已经实现并测量过这些不兼容替代方案。
初版用保存值与稍后的currentTime精确相等作断言,导致WebKit三项失败,两次读取
相差约15–27微秒;其中有旧版也有候选。最终改成核对保存值位于同一次刷新前后
原生读取的区间内,不引入任意容差。首轮记录保留,不能将测试错误登记成产品缺陷。
## 初始化、布局与正式配对
复用profile-core-layout.mjs取得当前源码真实CPU采样。构造采样约90207微秒,
其中insertAdjacentHTML约15793、模板init约14994;销毁采样约51139微秒,原生
video.load约32147、模板destroy约9743。采样总量不是所有构造的精确壁钟耗时,
原生时间也可能计到JS调用方;这是定位证据,不替代独立正式配对。当前数据没有
支持在这一轮增加模板缓存或把原生媒体释放延后;保留DOM/SSR/代理和同步清理行为。
布局/设置测试使用当前实际安装包,复核CORE-22已有优化仍生效。原生observer不在
构造中强制读取控件高度,fallback仍立即测量;尺寸、字幕位置与首次观察前销毁均
有断言。长设置列表的工作量保留原始附件,并核对所有引擎一致,未跨事件缓存可用项。
正式配对沿用BASE-06媒体、热身、五次样本、core/chapter两种配置和三组交替顺序。
新包run-rawoRh首轮Firefox因实测观察349ms失败,已由独立ENG-13修复当前适配层,
冻结数据和350ms门槛未改。同一安装包重测完成三引擎、108个旧新资源窗口,其中
54个候选窗口通过严格清理;详见observation-window-validation.json。
第二轮没有计时超阈值信号,但首轮Chromium销毁信号保留;只改观察窗口不构成
计时优化,不以重跑成功证明波动消失。体积始终review-required:现代208943 raw /
58756 gzip9 / 53660 Brotli6;比即时修改前增加12/10/12字节。原完整增量归因仍在
build-analysis.md,不把新增可访问性、设置树和失败恢复能力的成本说成TS工具运行时。
## 验收边界和后续维护
补充18项storage/auto-playback单元和新增浏览器测试的定向lint通过。包内架构文档
更新后重新执行yarn test:package:run-jl3UQr的36项运行时、5组旧类型、8组精确类型
均通过。与实际浏览器/计时使用的run-rawoRh逐文件比较,只有核心ARCHITECTURE.md
发生变化,所有其他打包文件一致;这里复用相同运行时字节的证据,不声称浏览器
曾运行新归档。完整包报告与差异哈希保存在收尾记录。
MOD-03的选择性优化、全部指定测量、旧新对比和权衡已形成可复跑证据。
ENG-PERF-01/02继续由REVIEW-01及最终候选复盘审查:体积增长是真实成本,间歇计时
信号不能简单宣布为噪声。未来源码/构建/依赖改变后,重新打包和执行相应验证。
这不是全项目、全插件、GPU/原生内存、物理设备或远端CI验收,也不是npm发布授权。
详细报告、样本、输入指纹和复跑命令见
[收尾记录](../baselines/core-performance-validation.json)。这次只新增测量/契约测试
及维护文档;生产优化保留在同任务前述检查点。回退该检查点并正常构建核心/i18n
可恢复冗余ARIA写入;回退当前提交只移除收尾测试/文档及任务完成记录。
+5 -2
View File
@@ -46,7 +46,10 @@ yarn test:browser,以及同一安装包的 yarn test:performance。legacy 必
进入运行时包。CORE-22 已移除设置导航的重复扫描和构造中的一次强制控件布局;不夸大其收益,
也不将原始 gzip/计时阈值上调。native load/DOM 销毁成本不通过异步延迟清理转移出计时区间。
ENG-PERF-01/02 的后续核心性能工作归 MOD-03,并在 REVIEW-01 重新审查。它们保持 open,
MOD-03已完成进度ARIA写入优化、原生存储契约/成本测量、初始化采样、布局复核及
三引擎实际安装包的三组配对,见[收尾记录](changes/2026-09-14-MOD-03-performance-acceptance.md)。
存储缓存方案因对象隔离和同步交错写入的兼容约束而未采用;保留变慢组及原始失败。
ENG-PERF-01/02 的后续审查归 REVIEW-01。它们保持 open,
表示不能批准发布,也不能宣称性能已经全面达标;保留相同设备媒体三组配对和原始样本。
核心结构及兼容自动化阶段的交付不删除这些任务、风险或后续依赖。
@@ -62,7 +65,7 @@ ReferenceError,发布 5.4.0 和当前候选均复现。较新 Node 的全局 n
chapter 的本轮四组合不能代替所有包,也不能代替它自己的最终进度/质量/全屏组合任务。
- EX-01/02/03 与 SITE:React/Vue、全部 demo/在线编辑器及远端资源;核心 Monaco 场景不是全站验收。
- REL-03、REVIEW-02:物理 Apple/Android、原生 PiP/AirPlay/方向/触摸、外部 SDK、codec/模型及压力环境。
- ENG/MOD 后续任务:完整 GitHub CI/CD、覆盖/提交索引、剩余脚本、性能优化及工具链采用决策。
- ENG/MOD 后续任务:完整 GitHub CI/CD、覆盖/提交索引、剩余脚本及工具链采用决策;性能风险继续在复盘审查。
- REL-09/02 和 REVIEW-01/02/03:逐包下一个 major、最终 tarball、三轮全项目复盘及发布批准。
包内 ARCHITECTURE.md 是实际源码地图;本目录保存迁移与验收记录。
+8
View File
@@ -46,6 +46,14 @@ Node CI 新增 Ubuntu/Windows 覆盖率 job,验证固定工具链并运行完
## 资源与性能验收
MOD-03已完成当前核心的选择性优化与热路径测量,见
[任务验收](changes/2026-09-14-MOD-03-performance-acceptance.md)及
[绑定样本和输入指纹](baselines/core-performance-validation.json)。滑块重复写入减少,
存储保持独立解析和交错更新契约;当前安装包三引擎布局12项、存储9项通过。
正式配对完整性和54个候选资源窗口通过,体积仍review-required,首轮计时信号保留。
重新安装run-jl3UQr验证了更新后的包文档;与计时用run-rawoRh相比只有ARCHITECTURE.md
内容变化,未将复用的相同运行时字节证据说成新一轮浏览器执行。
沿用 BASE-06:至少三组同环境旧版/候选配对,交替顺序;每种配置一次预热和五次计时样本。构造/就绪/播放 Promise/销毁阈值为 max(25%, 对应绝对值 2/50/10/2 ms)。压缩采用原始字节、gzip 9、Brotli 6,匹配相同格式与入口,增长超过 max(5%, 1024 bytes) 触发审查。
计时和体积触发审查不等于资源泄漏。候选资源检查严格要求销毁后无实例、DOM、proxy 监听器、RAF、剩余定时器和晚到回调,不以旧版 BASE-PERF-01 的残留作为容许值。计时阶段不装资源探针,资源探针清理自身计时器发生在记录之后。物理设备、GPU/浏览器原生内存仍不能靠这些计数证明无泄漏。
+3 -3
View File
@@ -4,7 +4,7 @@
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 255 项,范围 22 个包及工作区/示例。
状态:todo 53 / doing 18 / blocked 0 / done 184 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
状态:todo 53 / doing 17 / blocked 0 / done 185 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
@@ -412,7 +412,7 @@
| MOD-PLUGIN-01 | workspace<br>迁移插件生成器与类型化模板 | ENG-06, SITE-03 | 保留 create:plugin CLI;纯渲染/文件发布边界、TS 工厂/声明/测试/示例及维护指南 | 防止覆盖现有包或示例;失败回退;生成包可构建并通过严格类型、旧模块消费及测试;不自动修改既有包或运行安装发布 | M | done |
| MOD-02 | workspace<br>整理剩余开发/构建脚本与插件模板 | ENG-06, SITE-03, MOD-PLUGIN-01 | dev/build/utils/create-plugin 的 TS 与可测 CLI,模板同时提供旧 API | 旧脚本入口保留、新插件类型/测试/示例齐全,Lerna 改动单独取证 | M | done |
| MOD-DEV-01 | workspace<br>修复开发服务器失败状态并明确资源生命周期 | MOD-02 | 修复 Servor 占用端口却退出 0 的已复现问题;明确 HTTP/监听/热刷新连接与定时器的启动、失败和关闭责任 | 保持默认 8082、docs 页面、自动刷新和旧 dev 命令;端口冲突退出非零且不终止其他服务,连续启动/停止及编译错误恢复有实际验证;跨平台监听差异单独留证 | M | done |
| MOD-03 | workspace<br>测量并优化核心热路径 | CORE-22, ENG-08 | DOM 读写、进度更新、持久化、初始化的测量与改进 | 相同设备媒体多次比较,契约不变,收益及无效尝试记录;复用 BASE-06 的原始样本与测量限制,至少三组同环境旧新配对,不以单次变快宣称收益 | M | doing |
| MOD-03 | workspace<br>测量并优化核心热路径 | CORE-22, ENG-08 | DOM 读写、进度更新、持久化、初始化的测量与改进 | 相同设备媒体多次比较,契约不变,收益及无效尝试记录;复用 BASE-06 的原始样本与测量限制,至少三组同环境旧新配对,不以单次变快宣称收益 | M | done |
| MOD-04 | workspace<br>测量并优化重型插件/proxy | PKG-DANMUKU-09, PKG-MASK-06, PKG-MB-10, ENG-08 | 帧/队列/推理/音画同步与资源长期运行比较 | 不改默认算法/阈值,性能改善有证据;无收益则保留旧实现 | M | todo |
| MOD-05 | workspace<br>完成工具链与性能采用决策 | MOD-01, MOD-02, MOD-03, MOD-04, MOD-DEV-01 | 最终 runtime/packageManager/构建配置及性能台账 | 干净安装和全包检查通过;Bun 未采用有理由,不为状态强行切换 | M | todo |
@@ -637,7 +637,7 @@
- MOD-PLUGIN-01: [记录](changes/2026-09-14-MOD-PLUGIN-01-scaffold.md) [记录](baselines/scaffold-validation.json)
- MOD-02: [记录](changes/2026-09-14-MOD-02-library-tooling.md) [记录](baselines/library-tooling-validation.json)
- MOD-DEV-01: [记录](changes/2026-09-14-MOD-DEV-01-dev-server.md) [记录](baselines/dev-server-validation.json)
- MOD-03: [记录](changes/2026-09-14-MOD-03-slider-updates.md) [记录](baselines/slider-updates-validation.json)
- MOD-03: [记录](changes/2026-09-14-MOD-03-slider-updates.md) [记录](baselines/slider-updates-validation.json) [记录](changes/2026-09-14-MOD-03-performance-acceptance.md) [记录](baselines/core-performance-validation.json)
- REL-08: [记录](changes/2026-09-14-REL-08-release-ledger.md) [记录](baselines/release-ledger-validation.json) [记录](release-ledger.md) [记录](release-ledger.json)
- PKG-FACTORY-01: [记录](baselines/factory-assignment-gaps.json) [记录](baselines/factory-compatibility-proposals.json) [记录](factory-compatibility-decision.md) [记录](changes/2026-09-12-PKG-FACTORY-01-decision.md) [记录](type-compatibility-policy.md) [记录](baselines/factory-compatibility-validation.json) [记录](changes/2026-09-13-PKG-FACTORY-01-compatible-types.md)
- CORE-25: [记录](changes/2026-09-13-CORE-25-defaults-ssr.md) [记录](baselines/defaults-ssr-validation.json)
+14
View File
@@ -1,5 +1,19 @@
# 进度与证据
## MOD-03 核心热路径测量与优化完成
完成检查点23a4f22b7后的剩余验收:原生存储三引擎三组旧新9项、安装包布局/设置
12项、storage/auto-playback单元18项及定向lint通过。持久化保留独立对象及交错
设置写入语义,不以缓存改变旧调用;保留WebKit原测试时钟断言失败和最终区间断言。
Chromium真实首帧60次采样补充初始化/销毁归因,不把采样时长当作正式性能结果。
正式安装包三引擎三组配对及54次候选资源窗口见ENG-13证据,体积和间歇计时风险
仍open,继续交REVIEW-01审查。新安装run-jl3UQr通过36项运行时、5组旧类型、8组
精确类型;包内容只有ARCHITECTURE.md变化,运行时/声明与浏览器用包字节一致。
见[验收记录](changes/2026-09-14-MOD-03-performance-acceptance.md)及
[测量证据](baselines/core-performance-validation.json)。255项:185 done、17 doing、
53 todo。本次不关闭插件、真机、远端CI、三轮复盘及发布门槛。下一步继续剩余包的
兼容收尾和工程任务,按任务独立提交;VAST默认行为选择仍待用户回复。
## ENG-13 性能探针观察窗口修复完成
MOD-03新隔离包run-rawoRh通过36项运行时、5组旧类型和8组精确类型消费。正式配对
+8 -4
View File
@@ -24,11 +24,13 @@
"refactor/core-acceptance.md",
"refactor/baselines/core-acceptance-validation.json",
"refactor/changes/2026-09-14-MOD-03-slider-updates.md",
"refactor/baselines/slider-updates-validation.json"
"refactor/baselines/slider-updates-validation.json",
"refactor/changes/2026-09-14-MOD-03-performance-acceptance.md",
"refactor/baselines/core-performance-validation.json"
],
"compatibleResolution": "Attribute the growth to actual modules and build output, remove avoidable overhead while preserving APIs, and document any justified remaining cost against matching published entries.",
"closureCriteria": "Fresh isolated artifacts have reproducible raw/gzip9/Brotli6 results and an explicit size review; do not raise or overwrite the historical threshold to pass.",
"workspaceState": "First ENG-08 modern core measurement: 134037 to 207875 raw bytes, 35486 to 58374 gzip9, 32533 to 53326 Brotli6. Chapter remains below the combined relative/absolute review threshold. This is a review requirement, not a release approval. CORE-22 navigation phase: 208030 raw / 58429 gzip9 / 53361 Brotli6 modern bytes. Preferred-target revalidation removes a second panel scan at a cost of 55 gzip bytes over ENG-08; it does not resolve total bundle growth. Final CORE-22: modern 208037 raw / 58434 gzip9 / 53372 Brotli6; legacy 212218 / 59686 / 54412; ESM 361496 / 77141 / 70030. Navigation and initial-layout work were reduced, but total size remains above the historical threshold. MOD-03 and REVIEW-01 must review this before release. MOD-03 slider checkpoint: dynamic ARIA writes compare actual DOM before mutation. Main/legacy three paired groups per desktop engine pass operation/native-playback checks. Synthetic repeated-event timings include slower groups; main is 208943 raw / 58756 gzip9 / 53660 Brotli6, +10 gzip bytes from the immediate prechange artifact. Full installed BASE-06 pairing and remaining hotspots are still outstanding; this risk stays open."
"workspaceState": "First ENG-08 modern core measurement: 134037 to 207875 raw bytes, 35486 to 58374 gzip9, 32533 to 53326 Brotli6. Chapter remains below the combined relative/absolute review threshold. This is a review requirement, not a release approval. CORE-22 navigation phase: 208030 raw / 58429 gzip9 / 53361 Brotli6 modern bytes. Preferred-target revalidation removes a second panel scan at a cost of 55 gzip bytes over ENG-08; it does not resolve total bundle growth. Final CORE-22: modern 208037 raw / 58434 gzip9 / 53372 Brotli6; legacy 212218 / 59686 / 54412; ESM 361496 / 77141 / 70030. Navigation and initial-layout work were reduced, but total size remains above the historical threshold. MOD-03 and REVIEW-01 must review this before release. MOD-03 slider checkpoint: dynamic ARIA writes compare actual DOM before mutation. Main/legacy three paired groups per desktop engine pass operation/native-playback checks. Synthetic repeated-event timings include slower groups; main is 208943 raw / 58756 gzip9 / 53660 Brotli6, +10 gzip bytes from the immediate prechange artifact. Full installed BASE-06 pairing and remaining hotspots are still outstanding; this risk stays open. MOD-03 completion: native persistence (9 paired cases), installed layout/navigation (12 cases), Chromium first-frame CPU sampling, and fresh installed BASE-06 three-group comparisons are complete. Final formal candidate resource windows all pass; original 349ms harness failure and first Chromium destruction signal are retained. Size remains review-required. Storage caching was rejected to preserve independently parsed objects and synchronous interleaved settings. REVIEW-01 retains this open release review; completion of MOD-03 does not waive it."
},
{
"id": "ENG-PERF-02",
@@ -49,11 +51,13 @@
"refactor/core-acceptance.md",
"refactor/baselines/core-acceptance-validation.json",
"refactor/changes/2026-09-14-MOD-03-slider-updates.md",
"refactor/baselines/slider-updates-validation.json"
"refactor/baselines/slider-updates-validation.json",
"refactor/changes/2026-09-14-MOD-03-performance-acceptance.md",
"refactor/baselines/core-performance-validation.json"
],
"compatibleResolution": "Repeat paired measurements on the same environment, distinguish initialization and teardown work from host jitter, and optimize only after identifying a reproducible cost.",
"closureCriteria": "Explain repeat-group timing signals with retained samples and source fingerprints; do not infer a regression or improvement from a single group or expand timing allowances.",
"workspaceState": "First ENG-08 run: Firefox group 2 had core/chapter constructor delta 3/5 ms, WebKit group 3 chapter delta 3 ms, versus 2 ms absolute allowance. Other groups did not trigger. Candidate resource checks passed independently. Final run: Chromium/Firefox had no timing signals; WebKit group 1 core/chapter each increased 3 ms, with no signals in the other two groups. The intermittent review remains open. CORE-22 navigation phase: Chromium group 1 core/chapter destroy deltas 3.1/2.5 ms and group 3 chapter constructor delta 2.8 ms; WebKit group 1 chapter destroy delta 27 ms (71 to 98 ms); Firefox has no timing signals. Other groups do not reproduce those destroy signals. All 54 candidate resource probes pass. The timed fixture uses default settings disabled, so these measurements do not establish any timing effect from setting navigation changes. Final CORE-22: no constructor timing signals in any of the three engines; Chromium/Firefox have no timing signals. WebKit group 1 chapter destruction delta 44 ms and group 2 core delta 30 ms remain, group 3 has no signal. All 54 candidate resource probes pass. Chromium sampling identifies native load/DOM teardown cost but does not establish the cause of WebKit signals. MOD-03/REVIEW-01 retain the open review without changing allowances. MOD-03 slider checkpoint: dynamic ARIA writes compare actual DOM before mutation. Main/legacy three paired groups per desktop engine pass operation/native-playback checks. Synthetic repeated-event timings include slower groups; main is 208943 raw / 58756 gzip9 / 53660 Brotli6, +10 gzip bytes from the immediate prechange artifact. Full installed BASE-06 pairing and remaining hotspots are still outstanding; this risk stays open."
"workspaceState": "First ENG-08 run: Firefox group 2 had core/chapter constructor delta 3/5 ms, WebKit group 3 chapter delta 3 ms, versus 2 ms absolute allowance. Other groups did not trigger. Candidate resource checks passed independently. Final run: Chromium/Firefox had no timing signals; WebKit group 1 core/chapter each increased 3 ms, with no signals in the other two groups. The intermittent review remains open. CORE-22 navigation phase: Chromium group 1 core/chapter destroy deltas 3.1/2.5 ms and group 3 chapter constructor delta 2.8 ms; WebKit group 1 chapter destroy delta 27 ms (71 to 98 ms); Firefox has no timing signals. Other groups do not reproduce those destroy signals. All 54 candidate resource probes pass. The timed fixture uses default settings disabled, so these measurements do not establish any timing effect from setting navigation changes. Final CORE-22: no constructor timing signals in any of the three engines; Chromium/Firefox have no timing signals. WebKit group 1 chapter destruction delta 44 ms and group 2 core delta 30 ms remain, group 3 has no signal. All 54 candidate resource probes pass. Chromium sampling identifies native load/DOM teardown cost but does not establish the cause of WebKit signals. MOD-03/REVIEW-01 retain the open review without changing allowances. MOD-03 slider checkpoint: dynamic ARIA writes compare actual DOM before mutation. Main/legacy three paired groups per desktop engine pass operation/native-playback checks. Synthetic repeated-event timings include slower groups; main is 208943 raw / 58756 gzip9 / 53660 Brotli6, +10 gzip bytes from the immediate prechange artifact. Full installed BASE-06 pairing and remaining hotspots are still outstanding; this risk stays open. MOD-03 completion: native persistence (9 paired cases), installed layout/navigation (12 cases), Chromium first-frame CPU sampling, and fresh installed BASE-06 three-group comparisons are complete. Final formal candidate resource windows all pass; original 349ms harness failure and first Chromium destruction signal are retained. Size remains review-required. Storage caching was rejected to preserve independently parsed objects and synchronous interleaved settings. REVIEW-01 retains this open release review; completion of MOD-03 does not waive it."
},
{
"id": "BASE-LIFE-06",
+4 -2
View File
@@ -4537,13 +4537,15 @@
"CORE-22",
"ENG-08"
],
"status": "doing",
"status": "done",
"risk": "M",
"deliverable": "DOM 读写、进度更新、持久化、初始化的测量与改进",
"acceptance": "相同设备媒体多次比较,契约不变,收益及无效尝试记录;复用 BASE-06 的原始样本与测量限制,至少三组同环境旧新配对,不以单次变快宣称收益",
"evidence": [
"changes/2026-09-14-MOD-03-slider-updates.md",
"baselines/slider-updates-validation.json"
"baselines/slider-updates-validation.json",
"changes/2026-09-14-MOD-03-performance-acceptance.md",
"baselines/core-performance-validation.json"
]
},
{
+8
View File
@@ -231,6 +231,14 @@ Five timings of 1000 synthetic paused updates follow a 300-update warmup; operat
counts and actual playback are measured separately. Keep raw samples and do not
interpret these diagnostics as full initialization/resource or playback-FPS gates.
`storage-performance.spec.js` compares published and candidate playback records
in three alternating groups with actual video and localStorage. It records five
100-event timing samples separately from Storage/JSON instrumentation, verifies
fresh nested read results and interleaved unrelated settings, and checks paused
updates. Saved media time must fall between native reads immediately around the
refresh; exact equality with a later read is invalid when the clock advances.
This is a synchronous public-get interleaving test, not a multi-process race test.
JASSUB Firefox diagnostics retain the canonical failing cases. Set
`ARTPLAYER_JASSUB_OFFSCREEN=default` to exercise native capability selection.
`ARTPLAYER_JASSUB_ASYNC_RENDER=false` explicitly selects synchronous rendering;
+113
View File
@@ -0,0 +1,113 @@
import { expect, test } from './fixtures.js'
for (let group = 0; group < 3; group++) {
test(`playback persistence measurements and fresh-state contracts group ${group + 1}`, async ({ page }, testInfo) => {
const runs = []
for (const core of group % 2 ? ['candidate', 'published'] : ['published', 'candidate']) {
await page.goto(`/test/player.html?core=${core}&chapter=published`)
await page.evaluate(() => {
localStorage.setItem('artplayer_settings', JSON.stringify({ times: { another: 2 }, external: { retained: true }, volume: 0.7 }))
window.art = new window.Artplayer({ container: '.player', url: '/test/pattern.mp4', muted: true, autoPlayback: true, id: 'persistence-measurement' })
document.querySelector('#play').onclick = () => window.art.play()
})
await page.locator('#play').click()
await expect.poll(() => page.evaluate(() => window.art.playing && window.art.currentTime > 0.1)).toBe(true)
try {
const result = await page.evaluate(() => {
const art = window.art
const refresh = () => art.emit('video:timeupdate', new Event('timeupdate'))
for (let index = 0; index < 100; index++)
refresh()
// Timings run without replacing native Storage/JSON methods.
const samples = []
for (let sample = 0; sample < 5; sample++) {
const started = performance.now()
for (let index = 0; index < 100; index++)
refresh()
samples.push(performance.now() - started)
}
const original = { getItem: Storage.prototype.getItem, setItem: Storage.prototype.setItem, parse: JSON.parse, stringify: JSON.stringify }
const counts = { getItem: 0, setItem: 0, parse: 0, stringify: 0 }
Storage.prototype.getItem = function (...args) {
if (args[0] === art.storage.name)
counts.getItem++
return original.getItem.apply(this, args)
}
Storage.prototype.setItem = function (...args) {
if (args[0] === art.storage.name)
counts.setItem++
return original.setItem.apply(this, args)
}
JSON.parse = (...args) => {
counts.parse++
return original.parse(...args)
}
JSON.stringify = (...args) => {
counts.stringify++
return original.stringify(...args)
}
try {
for (let index = 0; index < 100; index++)
refresh()
}
finally {
Storage.prototype.getItem = original.getItem
Storage.prototype.setItem = original.setItem
JSON.parse = original.parse
JSON.stringify = original.stringify
}
// WebKit's native clock can advance between consecutive property reads.
const beforeRefresh = art.currentTime
refresh()
const afterRefresh = art.currentTime
const stored = art.storage.get()
const time = { beforeRefresh, afterRefresh }
const isolated = art.storage.get()
isolated.times.transient = 999
isolated.external.retained = false
const fresh = art.storage.get()
const calls = []
const get = art.storage.get
// A legal custom get can update unrelated settings between record read and save.
art.storage.get = function (key) {
calls.push(key ?? null)
const result = get.call(this, key)
if (key === 'times') {
const latest = get.call(this)
latest.external = { retained: true, revision: 'interleaved' }
localStorage.setItem(this.name, JSON.stringify(latest))
}
return result
}
try {
refresh()
}
finally {
art.storage.get = get
}
const merged = art.storage.get()
const pausedBefore = localStorage.getItem(art.storage.name)
art.pause()
refresh()
const pausedAfter = localStorage.getItem(art.storage.name)
return { samples, counts, time, stored, fresh, merged, calls, pausedBefore, pausedAfter }
})
runs.push({ core, group, result })
expect(result.stored.times['persistence-measurement']).toBeGreaterThanOrEqual(result.time.beforeRefresh)
expect(result.stored.times['persistence-measurement']).toBeLessThanOrEqual(result.time.afterRefresh)
expect(result.stored.times.another).toBe(2)
expect(result.stored.external).toEqual({ retained: true })
expect(result.fresh.times).not.toHaveProperty('transient')
expect(result.fresh.external).toEqual({ retained: true })
expect(result.merged.external).toEqual({ retained: true, revision: 'interleaved' })
expect(result.calls).toEqual(['times', null])
expect(result.pausedAfter).toBe(result.pausedBefore)
}
finally {
await page.evaluate(() => window.art.destroy(false))
await testInfo.attach(`persistence-${core}`, { contentType: 'application/json', body: JSON.stringify(runs.at(-1) || { core, group, failedBeforeMeasurements: true }) })
}
}
await testInfo.attach('persistence-paired-summary', { contentType: 'application/json', body: JSON.stringify({ runs, limitation: 'Actual video and native same-origin localStorage, followed by synthetic timeupdate dispatch while playing. 100 warmups and five 100-event timing samples without native method wrappers; a separate instrumented window reports Storage/JSON calls. A custom public get tests synchronous interleaving, not a concurrent multi-process storage race. No storage implementation or write cadence change is made.' }) })
})
}