深入剖析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 的情况,主要是safariwebworker的兼容,也会降级到_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,也就是markname
  • 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

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

相关推荐
森叶10 分钟前
Electron 安装包 asar 解压定位问题实战
前端·javascript·electron
drebander13 分钟前
ubuntu 安装 chrome 及 版本匹配的 chromedriver
前端·chrome
软件技术NINI23 分钟前
html知识点框架
前端·html
深情废杨杨26 分钟前
前端vue-插值表达式和v-html的区别
前端·javascript·vue.js
GHUIJS27 分钟前
【vue3】vue3.3新特性真香
前端·javascript·vue.js
markzzw31 分钟前
我在 Thoughtworks 被裁前后的经历
前端·javascript·面试
众生回避33 分钟前
鸿蒙ms参考
前端·javascript·vue.js
洛千陨33 分钟前
Vue + element-ui实现动态表单项以及动态校验规则
前端·vue.js
GHUIJS1 小时前
【vue3】vue3.5
前端·javascript·vue.js
&白帝&2 小时前
uniapp中使用picker-view选择时间
前端·uni-app