eb performance

eb performance test

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name         eb performance
// @namespace    http://tampermonkey.net/
// @version      0.1.6
// @description  eb performance test
// @author       timluo465
// @match        http://*/*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none
// @license      MIT
// ==/UserScript==

const defaultStyle = "font-size:14px";
const focalStyle = "font-weight:700;font-size:16px";

(function () {
  "use strict";
  console.log("开始初始化eb性能分析插件");
  const recordFuns = [];
  const moduleObj = {};

  const createInterval = function (callback) {
    const interval = setInterval(function () {
      const res = callback();

      if (res) {
        clearInterval(interval);
      }
    }, 20);
  };

  createInterval(function () {
    if (window.mobx) {
      initMobx();
    }
    return !!window.mobx;
  });

  createInterval(function () {
    if (window.React) {
      initReact();
    }
    return !!window.React;
  });

  const createPerformanceTimer = function (fn, opts) {
    return function (...args) {
      const { fnName = "" } = opts || {};
      const now = performance.now();
      const res = fn(...args);
      const last = performance.now();
      const time = (last - now).toString();
      const spentTime = time.substring(0, time.indexOf(".") + 3);

      if (spentTime > 5) {
        const consoleFun = spentTime > 50 ? console.error : console.warn;
        recordFuns.push({ func: this, time: spentTime });

        consoleFun(
          `%c${fnName}%c 耗时 %c${spentTime} ms%c, 参数为:%o \n${
            res ? `返回结果:%o` : "无返回结果"
          }`,
          focalStyle,
          defaultStyle,
          focalStyle,
          defaultStyle,
          args,
          res
        );
      }

      return res;
    };
  };

  const call = Function.prototype.call;

  Function.prototype.call = function () {
    const now = performance.now();
    const res = call.apply(this, arguments);
    const last = performance.now();
    const time = (last - now).toString();
    const spentTime = time.substring(0, time.indexOf(".") + 3);

    if (spentTime > 5) {
      const module = getModule();

      if (module) {
        const moduleName = `@weapp/${module}`;
        const consoleFun = spentTime > 50 ? console.error : console.warn;
        recordFuns.push({ func: this, time: spentTime });

        if (module && moduleObj[moduleName]) {
          const { all, serious } = moduleObj[moduleName];

          moduleObj[moduleName] = {
            ...moduleObj[moduleName],
            all: all + 1,
          };

          if(spentTime > 50){
            moduleObj[moduleName].serious = serious + 1;
          }
        } else {
          moduleObj[moduleName] = {
            moduleName: moduleName,
            all: 1,
            serious: 1,
          };
        }
        consoleFun(
          `%c未知方法执行耗时 %c${spentTime} ms%c,来源模块:%c@weapp/${module}%c \n点击定位方法:%o \n${
            res ? `返回结果:%o` : "无返回结果"
          }`,
          defaultStyle,
          focalStyle,
          defaultStyle,
          focalStyle,
          defaultStyle,
          this,
          res
        );
      }
    }
    return res;
  };

  function getModule(isMobx) {
    //创建一个Error来获取Error所在的位置及其堆栈跟踪
    const e = new Error();
    const regex = /\((.*):(\d+):(\d+)\)$/;

    if (!isMobx) {
      const stak = e.stack.split("\n");
      const match = regex.exec(stak[stak?.length - 1]);
      const module = match?.[1].match(/(?<=build\/).*?(?=\/static)/)?.[0] || "";

      return module;
    }
  }

  function initMobx() {
    const mobx = window.mobx;

    ["toJS", "computed", "runInAction"].forEach(function (act) {
      const originalFn = mobx[act];

      mobx[act] = createPerformanceTimer(originalFn, {
        fnName: `mobx.${act}`,
      });

      Object.keys(originalFn).forEach(function (key) {
        mobx[act][key] = originalFn[key];
      });
    });

    Object.keys(mobx.observable).forEach(function (action) {
      const originalFn = mobx.observable[action];

      mobx.observable[action] = createPerformanceTimer(originalFn, {
        fnName: `mobx.observable.${action}`,
      });
    });

    console.log("Mobx性能分析插件初始化完成!");
  }

  function initReact() {
    const React = window.React;

    [
      "useEffect",
      "useCallback",
      "useState",
      "useMemo",
      "useRef",
      "memo",
    ].forEach(function (hook) {
      const originalHook = React[hook];

      React[hook] = createPerformanceTimer(originalHook, {
        fnName: `React.${hook}`,
      });
    });

    console.log("React Hooks性能分析插件初始化完成!");
  }

  function print() {
    const printObj = [];
    const moduleArrays = [];
    Object.keys(moduleObj).forEach(function (key) {
      moduleArrays.push(moduleObj[key]);
    });
    const sortModuleArrays = moduleArrays.sort((a, b) => {
      return b.all - a.all;
    });

    sortModuleArrays.forEach((array) => {
      printObj.push({
        前端模块: array.moduleName,
        "问题数(所有)": array.all,
        "问题数(耗时大于50ms)": array.serious,
      });
    });

    console.table(printObj);
  }

  function getRecords() {
    const funs = [];
    const beyondThresholdFuns = [];
    const threshold = 50;
    let times = 0;

    recordFuns.forEach((recordFun) => {
      funs.push(recordFun);

      if (recordFun.time > threshold) {
        beyondThresholdFuns.push(recordFun);
        times++;
      }
    });

    console.log(
      `截至当前已发现性能问题点共计${recordFuns.length}个,大于${threshold}ms的问题共计${times}个 \n所有记录:%o\n大于${threshold}ms的记录:%o`,
      funs,
      beyondThresholdFuns
    );

    return;
  }
  window.performanceTools = { print, getRecords };
})();