eb performance

eb performance test

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==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 };
})();