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

相关推荐
若安程序开发5 小时前
WEBweb前端OPPO手机商城网站项目
前端·智能手机
范德萨_5 小时前
JavaScript 实用技巧(总结)
开发语言·前端·javascript
执携5 小时前
Vue Router (匹配当前路由的链接和类名配置)
前端·javascript·vue.js
若安程序开发5 小时前
web华为商城前端项目4页面
前端·华为
一枚前端小能手6 小时前
🏷️ HTML 属性参考 - 常用与全局属性的行为、兼容性与最佳实践
前端·javascript·html
付十一6 小时前
更新!Figma MCP + Cursor:大前端时代的UI到代码自动化
android·前端·ai编程
万岳科技程序员小金6 小时前
多端统一的教育系统源码开发详解:Web、小程序与APP的无缝融合
前端·小程序·软件开发·app开发·在线教育系统源码·教育培训app开发·教育培训小程序
软件架构师-叶秋6 小时前
Vue3+tyepescript+ElementPlus+Axios前端技术栈
前端·vue3·elementplus
AAA阿giao6 小时前
HTML/CSS/JS 页面渲染机制:揭秘浏览器如何将平凡代码点化为视觉魔法
前端·css·html
lichenyang4536 小时前
从零到一:编写一个简单的 Umi 插件并发布到 npm
前端·react.js·前端框架