深入剖析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,或者在其他未知环境中使用简单的降级函数来模拟性能标记的功能。

相关推荐
卸任5 小时前
Vibe coding工具使用心得
前端·ai编程
brien96 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance6 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M6 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写6 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李6 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易6 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马7 小时前
前沿视界
前端
kyriewen7 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易7 小时前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员