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