2

整体架构设计

项目地址【部分代码】
注意点:

1.xhr “重写”

import { dispatch } from "../event";
import { AJAX_RESPONSE_TIME, AJAX_STATUS_ERROR } from "../listen/type";

const xhrMdifiy = (
  options = {
    witheList: [],
  }
) => {
  // 全局变量
  const win = window;
  // 标准ajax
  const XMLHttpRequest = win.XMLHttpRequest;
  // fetch
  const fetch = win.fetch;
  //out XML
  const OutXMLHttpRequest = function () {
    const startTime = Date.now();
    const xhr = new XMLHttpRequest();
    const self = this;
    const readystatechangeEvent = [];
    const onerrorEvent = [];
    let body = null;
    const rHeaders = [];
    let type = '';
    const catchNormalRequestStatus = function (e) {
      const { currentTarget } = e;
      const { response, responseURL } = currentTarget;
      const endTime = Date.now();
      if (xhr.readyState === XMLHttpRequest.DONE) {
        if (xhr.status === 200) {
          let diffTime = endTime - startTime;
          dispatch(AJAX_RESPONSE_TIME, diffTime);
        } else {
          const requestHeaders = rHeaders.reduce((p, q) => {
            return {
              ...p,
              [q[0]]: q[1],
            };
          }, {});

          if (typeof body === "string") {
            body = body;
          }

          if (body instanceof FormData) {
            const bCopy = {};
            for (let pair of formData.entries()) {
              if (bCopy[1] instanceof Blob) {
                bCopy[pair[0]] = {
                  fileName: bCopy[1].fileName,
                  size: bCopy[1].size,
                };
              } else {
                bCopy[pair[0]] = pair[1];
              }
            }
          }

          if (body instanceof Blob) {
            const bCopy = {};
            bCopy = {
              fileName: body.fileName,
              size: body.size,
            };
          }

          if (body instanceof Object) {
            body = JSON.stringify(body);
          }
          const postData = {
            type,
            body,
            response,
            responseURL,
            requestHeaders,

          }
          console.log(postData)
          dispatch(AJAX_STATUS_ERROR, postData);
        }
      }
    };
    //
    readystatechangeEvent.push(catchNormalRequestStatus);
    // 代理 xhr 对象
    for (let key in xhr) {
      if (["setRequestHeader", "send", 'open'].includes(key)) {
        continue;
      }
      Object.defineProperty(self, key, {
        get() {
          if (typeof xhr[key] === "function") {
            return xhr[key].bind(xhr);
          }
          return xhr[key];
        },
        set(arg) {
          switch (key) {
            case "onreadystatechange": {
              const fn = arg;
              fn && readystatechangeEvent.push(fn);
              break;
            }
            default: {
              xhr[key] = arg;
            }
          }
        },
      });
    }
    // 重写 为了获取 请求类型
    self.open = function (...arg) {
      type  = arg[0]
      xhr.open.apply(xhr, arg)
    }
    // 重写为了获取 发送数据
    self.send = function (data) {
      body = data;
      xhr.send(data);
    };

    self.setRequestHeader = function (...arg) {
      rHeaders.push(arg);
      xhr.setRequestHeader(...arg);
    };
    // 检查状态变更 【默认注入一个监听事件】
    xhr.onreadystatechange = function (e) {
      readystatechangeEvent.forEach((fn) => {
        if (typeof fn === "function") {
          fn.call(xhr, e);
        }
      });
    };
    return self;
  };
  win.XMLHttpRequest = OutXMLHttpRequest;
};

export default xhrMdifiy;

2.资源加载 及 代码报错

import { LOAD_SOURCE_ERROR, SCRIPT_EXECUTE_ERROR } from "../listen/type";
import { dispatch, on } from "../event";
import { event } from "@l6zt/cutils";
const win = window;
const doc = window.document;
/*
 处理文件资源加载报错  标签中必须有【crossorigin="anonymous"】
 <script src="xx"  crossorigin="anonymous" ></script>
】
*/
event.on(win, 'error', (e) => {
  const { message, filename, lineno, colno, srcElement } = e;
  if (filename) {
    const payload = {
      message,
      filename,
      lineno,
      colno,
    }
    console.log(payload)
    dispatch(SCRIPT_EXECUTE_ERROR,  payload);
  }
});
// 观察资源加载情况 【观察 docment ”媒体元素“ 插入情况】
const observer = new MutationObserver((mutationsList, observer) => {
  mutationsList.forEach((mutation) => {
    const { type, addedNodes } = mutation;
    if (type === "childList") {
      addedNodes.forEach((el) => {
        if ( [HTMLScriptElement, HTMLImageElement,HTMLVideoElement, HTMLAudioElement, Image ].find((C) => el  instanceof C ) ) {
          event.on(el, 'error', (e) => {
            const { target } = e;
            const payload = {
              type: target.localName,
              src: target.getAttribute('src') || target.getAttribute('href')
            }
            console.log(payload)
            dispatch(LOAD_SOURCE_ERROR, payload)
          })
        }
      });
    }
  });
});

observer.observe(doc, { attributes: true, childList: true, subtree: true });

3.性能监控 【例子】

const win = window

win.addEventListener('load', function() {
  const perfData = window.performance.timing;
  const pageLoadTime = perfData.loadEventEnd - perfData.navigationStart;
  const connectTime = perfData.responseEnd - perfData.requestStart;
  const renderTime = perfData.domComplete - perfData.domLoading;
});

方糖先生
1.1k 声望1.8k 粉丝