javascript性能分析核心是在函数入口出口插入performance.now()时间采集逻辑计算差值,推荐手动埋点(装饰器封装)或自动埋点(proxy劫持),需区分环境、采样控制、避免高频打点,并结合performanceobserver追踪异步任务。

在 JavaScript 运行时性能分析中,通过代码埋点统计函数执行耗时,核心是**在函数入口和出口插入时间采集逻辑,计算差值**。这种方式轻量、可控,适合定位具体函数的性能瓶颈,无需依赖浏览器 DevTools 或复杂 APM 工具。
手动埋点:performance.now() + 包装函数
使用 performance.now() 获取高精度时间戳(微秒级,不受系统时间调整影响),是最推荐的基础方式。
- 在函数开始前记录起始时间
- 在函数结束后记录结束时间,相减即为耗时
- 建议将埋点逻辑封装成可复用的装饰器(Decorator)或高阶函数,避免重复写样板代码
示例:
function timeLog(label) {
return function (target, propertyKey, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args) {
const start = performance.now();
const result = originalMethod.apply(this, args);
const end = performance.now();
console.log(`[${label}] ${propertyKey} 耗时: ${(end - start).toFixed(2)}ms`);
return result;
};
};
}
<p>// 使用(仅限类方法,需启用装饰器语法)
class ApiClient {
@timeLog('API')
fetchUser(id) {
return fetch(<code>/api/user/${id}</code>).then(r => r.json());
}
}</p>自动埋点:Proxy 劫持 + 函数重写
对已有对象的方法批量添加耗时统计,适合不便于修改源码或需临时观测多个函数的场景。
- 用
Proxy拦截对象属性访问,对函数类型属性动态包装 - 保留原始函数引用,避免影响调用链和 this 绑定
- 可按需开启/关闭,支持过滤方法名或阈值告警(如 >100ms 打印警告)
示例:
function instrumentMethods(obj, options = {}) {
const { label = 'Instrument', threshold = 0 } = options;
const handler = {
get(target, prop) {
const value = target[prop];
if (typeof value === 'function') {
return function (...args) {
const start = performance.now();
const result = value.apply(target, args);
const end = performance.now();
const duration = end - start;
if (duration > threshold) {
console.warn(`[${label}] ${prop} 耗时超限: ${duration.toFixed(2)}ms`);
}
return result;
};
}
return value;
}
};
return new Proxy(obj, handler);
}
<p>// 使用
const api = instrumentMethods({ getUser: () => sleep(200) }, { threshold: 50 });</p>生产环境友好实践
埋点代码不能拖慢线上性能,也不能污染日志。需注意以下几点:
- 只在开发或灰度环境启用耗时统计,用
process.env.NODE_ENV === 'development'或配置开关控制 - 避免高频函数(如 render、mousemove 回调)直接打点;可采样(如每 10 次执行统计 1 次)或聚合上报
- 不依赖
console.time()—— 它是调试 API,不保证精度,且无法程序化获取数值 - 若需长期监控,应将耗时数据聚合后上报(如平均值、P95、错误率),而非逐条打印
配合 PerformanceObserver 做异步任务追踪
对于 Promise、setTimeout、fetch 等异步操作,单纯包裹函数无法覆盖整个生命周期。可结合 PerformanceObserver 监听 navigation、resource、mark、measure 等条目。
- 在关键异步操作前后打自定义 mark:
performance.mark('api-start')/performance.mark('api-end') - 用
performance.measure()关联两个 mark,生成可统计的 measure 条目 - 用
PerformanceObserver收集并上报 measure 数据
这样能统一追踪同步+异步耗时,且与浏览器性能时间线对齐。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











