使用 performance.mark() 和 performance.measure() 可获取微秒级耗时,需精准定位计算起止点、显式调用 measure 并严格匹配 mark 名,配合防错处理与清理机制确保数据准确有效。

直接用 performance.mark() 打起点和终点,再调用 performance.measure() 关联两者,就能拿到微秒级精度的耗时——关键在于起点和终点必须落在任务真正开始执行、真正完成输出的准确位置。
找准“开始”和“结束”的真实时机
复杂计算任务常涉及异步、循环、状态更新等环节,不能简单把函数调用入口当起点、return 当终点。
- 起点建议打在数据就绪、计算逻辑即将触发的那一刻,比如:
performance.mark('calc-start')放在requestIdleCallback回调内,或setTimeout(() => { /* 开始计算 */ }, 0)的第一行 - 结束点要等结果真正可用:若计算后需格式化、校验或写入状态,mark 应放在这些步骤之后;若返回 Promise,应在
.then()或await后立即打点,如performance.mark('calc-complete') - 避免在 for 循环内部高频打点,否则污染 Timeline 且无业务意义;一次任务只打一对有语义的 mark
正确配对 mark 与 measure
measure 不是自动发生的,必须显式调用,且参数必须严格匹配已注册的 mark 名。
- 确保两个 mark 都已成功执行:可先用
performance.getEntriesByName('calc-start').length判断是否存在,再执行 measure - 调用格式为:
performance.measure('calc-duration', 'calc-start', 'calc-complete'),注意字符串完全一致(区分大小写、空格) - 若 mark 名重复(如组件复用导致多次
mark('calc-start')),measure 默认取最后一次,易误判;推荐加轻量唯一标识,例如`calc-start-${Date.now()}`
安全提取并验证结果
measure 创建后不会自动暴露,需主动查询或监听,避免手动轮询。
- 即时提取:调用
performance.getEntriesByName('calc-duration', 'measure')获取数组,取[0]?.duration即为毫秒值 - 防错处理:该数组可能为空(如页面跳转导致 end 未打、或 mark 被清理),使用前应判空
- 替代方案:用
PerformanceObserver监听measure类型条目,配置{ entryTypes: ['measure'] },在回调中过滤entry.name === 'calc-duration'后处理
避免常见陷阱
看似简单,但几个细节出错就会拿不到有效数据。
-
performance.mark()若传入已存在的 name,Chrome 和 Firefox 会同步抛SyntaxError,中断后续逻辑——务必检查或加时间戳后缀 - 不要用
performance.getEntriesByName('calc-start')[0].startTime和getEntriesByName('calc-complete')[0].startTime手动相减:数组索引不可靠,且无法保证时序,measure 才是语义明确、浏览器原生保障的计算方式 - 高频任务需定期清理:
performance.clearMarks()或按前缀清理(如performance.clearMarks('calc-')),防止超出 150 条 entry 限制










