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

2023-11-23 14:59:15 浏览数 (1)

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 的情况,主要是safariwebworker的兼容,也会降级到_definePolyfillMarks。其他正常的情况下,会返回两个函数:

代码语言:javascript复制
{
  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,也就是markname
  • startTime,从performance接口拿到的startTime,再加上timeOrigin,其实这个值就是时间戳了。

降级到_definePolyfillMarks

代码语言:javascript复制
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

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

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

startTimeDate.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模块非常简单,主要暴露markgetMarks函数,用来标记和读取性能数据。

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

0 人点赞