配了三年性能监控,今天才发现 JS 执行时间的去向全被浏览器标出来了——Self-Profiling Markers 把这件事彻底变了
配了三年性能监控,今天才发现 JS 执行时间的去向全被浏览器标出来了——Self-Profiling Markers 把这件事彻底变了
用户说页面卡,你抓了 Lighthouse、接了 Performance API、装了付费监控 SDK,翻了半天还是找不到根子在哪——大多数时候瓶颈根本不在你的 JS 代码里,是在浏览器自己在跑 GC、做样式计算、或者在重绘。
但你没法证明。采样 profiling 只能看到 JS call stack,看不到 call stack 之间的空隙浏览器在干什么。2026 年 7 月,一个叫 Self-Profiling Markers 的更新悄悄进了 Chrome,把这件事彻底变了。
旧 profiling 工具的盲区
传统的 JS profiling 只记录 JS 执行时的情况。采样频率设成 10ms,profiler 就每 10ms 停一下,看当前 call stack 长什么样,然后继续。
问题在哪?采样只能抓到 JS 在跑的时候,call stack 为空的时间段你根本不知道发生了什么——可能是 GC 在跑,可能是样式在重算,可能是 layout 被触发了。这些工作打断了 JS 执行,但它们不在你的 profile 里。
结果是:你优化了半天的那个「热点函数」,可能只占用户感受到的卡顿的 30%,剩下 70% 是浏览器自己的开销,但你看不到。
Markers 是什么
Self-Profiling Markers 是 JS Self-Profiling API 的扩展。Chrome 94 就支持了 Profiler 接口,但那时候每个 sample 只有 call stack 信息。2026 年 7 月的更新给每个 sample 加了一个 marker 字段,标识采样时浏览器在干什么。
marker 的值一共有六种:
- script — JS 引擎在执行你的代码
- gc — 垃圾回收在跑
- style — 样式计算(CSS selector 匹配)
- layout — 布局计算(几何信息更新)
- paint — 绘制
- other — 其他浏览器工作
这样 profile 里就不再只有 call stack 之间的空隙,而是有空隙的原因——gc 表示垃圾回收占用了这段时间,style 表示样式计算在拖累你。
怎么用
用法和原来的 Profiler API 完全一样,不需要改任何代码:
“`javascript
const profiler = new Profiler({
sampleInterval: 10,
maxBufferSize: 10000,
});
// 监控你的业务逻辑
await doExpensiveWork();
const profile = await profiler.stop();
console.log(JSON.stringify(profile));
“`
返回的 profile 里,每个 sample 多了一个 marker 字段:
“`javascript
{
“samples”: [
{
“timestamp”: 12345,
“stackId”: 0,
“marker”: “script” // JS 在跑
},
{
“timestamp”: 12355,
“stackId”: null, // 没有 call stack
“marker”: “gc” // GC 在跑,这段时间 JS 被完全暂停
},
{
“timestamp”: 12365,
“stackId”: null,
“marker”: “style” // 样式重算
}
]
}
“`
stackId 为 null 的 sample 表示这段时间 JS 没有在执行,marker 告诉你原因。
能解决什么问题
找到被 GC 吃掉的时间。 GC 是 JavaScript 的天敌,但它不体现在普通 profiling 里。marker=gc 的 sample 数量如果占你 profile 的 20% 以上,基本可以确定是内存分配模式有问题。
区分样式开销和 JS 开销。 你以为页面卡是 JS 太重,但 style marker 告诉你 40% 的时间在跑 CSS selector 匹配——这时候应该优化 CSS 而不是重构 JS。
验证优化效果。 改了代码之后跑一次 profile,marker 分布变没变,一目了然。
真实案例
Facebook(这个 API 的主要推动方)在自己的生产环境里跑了一年,发现很多「JS 性能问题」的真实原因是 GC 和 layout,而他们的 JS 代码本身没问题。找到根子之后,修复路径完全不同。
浏览器支持
这个更新在 2026 年 7 月进入 Chrome(chromestatus 显示 Feature owners 是 Microsoft 的工程师)。Safari 和 Firefox 暂无信号,跨浏览器使用还是要做 feature detection:
“`javascript
if (“Profiler” in globalThis) {
// Markers 支持需要额外检测
// 目前只有 Chrome 94+ 有完整支持
}
“`
怎么落地
不需要接任何 SDK,不需要装任何包,直接用浏览器原生 API。生产环境建议采样跑,比如每 60 秒里跑 5 秒,把数据上报到你的监控系统:
“`javascript
// 每分钟采样 5 秒
setInterval(() => {
const profiler = new Profiler({ sampleInterval: 10, maxBufferSize: 5000 });
setTimeout(async () => {
const profile = await profiler.stop();
sendToAnalytics(profile); // 上报 marker 分布
}, 5000);
}, 60000);
“`
profile 本身比较小(纯文本),上报成本可控。
配了三年性能监控,今天才发现 profiling 只能看到 JS,看不到 JS 停下来的时候浏览器在干什么——Self-Profiling Markers 把这个盲区彻底关了。下次用户说卡,先跑一次 profiler,看看 script 以外的时间占比,这才是真正的瓶颈所在。
评论区
登录后可评论。