深入剖析vscode工具函数(十二)Performance

performance的定义

javascript 复制代码
function _define() {

  // Identify browser environment when following property is not present
  // https://nodejs.org/dist/latest-v16.x/docs/api/perf_hooks.html#performancenodetiming
  if (typeof performance === 'object' && typeof performance.mark === 'function' && !performance.nodeTiming) {
   // in a browser context, reuse performance-util

   if (typeof performance.timeOrigin !== 'number' && !performance.timing) {
    // safari & webworker: because there is no timeOrigin and no workaround
    // we use the `Date.now`-based polyfill.
    return _definePolyfillMarks();

   } else {
    // use "native" performance for mark and getMarks
    return {
     mark(name) {
      performance.mark(name);
     },
     getMarks() {
      let timeOrigin = performance.timeOrigin;
      if (typeof timeOrigin !== 'number') {
       // safari: there is no timerOrigin but in renderers there is the timing-property
       // see https://bugs.webkit.org/show_bug.cgi?id=174862
       timeOrigin = performance.timing.navigationStart || performance.timing.redirectStart || performance.timing.fetchStart;
      }
      const result = [{ name: 'code/timeOrigin', startTime: Math.round(timeOrigin) }];
      for (const entry of performance.getEntriesByType('mark')) {
       result.push({
        name: entry.name,
        startTime: Math.round(timeOrigin + entry.startTime)
       });
      }
      return result;
     }
    };
   }

  } else if (typeof process === 'object') {
   // node.js: use the normal polyfill but add the timeOrigin
   // from the node perf_hooks API as very first mark
   const timeOrigin = performance?.timeOrigin ?? Math.round((require.__$__nodeRequire || require)('perf_hooks').performance.timeOrigin);
   return _definePolyfillMarks(timeOrigin);

  } else {
   // unknown environment
   console.trace('perf-util loaded in UNKNOWN environment');
   return _definePolyfillMarks();
  }
 }

这段代码是由三个分支组成的,分别是三个条件:

  • 浏览器环境,存在performance对象。
  • node环境
  • 其他未知环境

其中第二个分支和第三个分支都是走_definePolyfillMarks 来返回结果。

在浏览器环境中,又判断了timeOrigin 的情况,主要是safari和webworker的兼容,也会降级到_definePolyfillMarks。其他正常的情况下,会返回两个函数:

ini 复制代码
{
  mark(name) {
   performance.mark(name);
  },
  getMarks() {
   let timeOrigin = performance.timeOrigin;
   if (typeof timeOrigin !== 'number') {
    // safari: there is no timerOrigin but in renderers there is the timing-property
    // see https://bugs.webkit.org/show_bug.cgi?id=174862
    timeOrigin = performance.timing.navigationStart || performance.timing.redirectStart || performance.timing.fetchStart;
   }
   const result = [{ name: 'code/timeOrigin', startTime: Math.round(timeOrigin) }];
   for (const entry of performance.getEntriesByType('mark')) {
    result.push({
     name: entry.name,
     startTime: Math.round(timeOrigin + entry.startTime)
    });
   }
   return result;
  }
 };
}

mark就完全是performance.mark的功能,然后getMarks将返回一个数组,数组里面是两个属性:

  • name,也就是mark的name
  • startTime,从performance接口拿到的startTime,再加上timeOrigin,其实这个值就是时间戳了。

降级到_definePolyfillMarks

ini 复制代码
function _definePolyfillMarks(timeOrigin) {

 const _data = [];
 if (typeof timeOrigin === 'number') {
  _data.push('code/timeOrigin', timeOrigin);
 }

 function mark(name) {
  _data.push(name, Date.now());
 }
 function getMarks() {
  const result = [];
  for (let i = 0; i < _data.length; i += 2) {
   result.push({
    name: _data[i],
    startTime: _data[i + 1],
   });
  }
  return result;
 }
 return { mark, getMarks };
}

这个降级函数非常简单,mark接口存入的是Date.now(),getMarks取出来的startTime就是当时存入的Date。

关于startTime和Date.now

startTime 是PerformanceEntry对象的一个属性,表示开始时间,单位是毫秒。

Date.now() 是 JavaScript 的一个方法,返回当前时间的 Unix 时间戳,单位也是毫秒。Unix 时间戳是从 1970 年 1 月 1 日 00:00:00 UTC(协调世界时)到当前时间的总毫秒数。

startTime 和 Date.now() 的主要区别在于它们的参考点不同:

  • startTime 的参考点是 performance.timeOrigin,即性能时间线的起点。性能时间线是一个记录了所有性能相关事件(如标记和测量)的时间线。在大多数浏览器中,performance.timeOrigin 的值等于 performance.timing.navigationStart,即当前页面的导航开始时间。因此,startTime 表示的是从页面导航开始到创建性能标记的时间。
  • Date.now() 的参考点是 Unix 纪元(1970 年 1 月 1 日 00:00:00 UTC)。因此,Date.now() 表示的是从 Unix 纪元到当前时间的总时间。

所以VSCode在这里使用performance.timeOrigin 加上startTime ,这个值就和Date.now() 是一个量级了。

小结一下

在VSCode中,实现performance模块非常简单,主要暴露mark和getMarks函数,用来标记和读取性能数据。

performance是一个灵活的工具函数,根据不同的执行环境提供性能测量和调试工具的支持。它可以在浏览器环境和node.js环境中使用原生的性能API,或者在其他未知环境中使用简单的降级函数来模拟性能标记的功能。

相关推荐
前端snow6 小时前
ai agent --- postgreSQL 关系型数据库
前端
卷无止境7 小时前
ECharts:把数据变成故事的可视化利器
前端
Eric_见嘉7 小时前
在职前端 Skill 和 MCP 分享
前端·后端·agent
liangshanbo12158 小时前
面试题:如何优化 Webpack 的打包速度?
前端·webpack·node.js
wengad8 小时前
从 wangEditor 迁到 wangEditor-next
前端·javascript·vue.js
行者-全栈开发9 小时前
【前端/JS框架】CVE-2026-3854:GitHub Enterprise Server X-Stat注入XSS漏洞深度剖析与紧急修复指南
前端·javascript·github
计算机魔术师10 小时前
AMD砸82亿买下李飞飞,这次不卖芯片卖什么?
前端
hzxpaipai10 小时前
杭州企业官网怎么建设?从策划到上线的5步建站方法
运维·服务器·前端·网络
怕浪猫11 小时前
2026年金九银十,我面了22个前端
前端·javascript·面试
IT_陈寒11 小时前
Vue 这个响应式陷阱,我的头发都掉没了
前端·人工智能·后端