前端性能监控,设置监控超时的任务,回传到服务器前端
完整代码以下ios
// 在src/utils/PerformanceMonitor.js export default class PerformanceMonitor { constructor() { // 设置基础毫秒 this.SEC = 1000 // 设置超时时差 this.TIMEOUT = 10 * this.SEC // 基础配置,上传数据 this.config = {} } init(option) { // 向前兼容 if (!window.performance) return false const { url, timeoutUrl, method = 'POST', timeout = 10000 } = option this.config = { url, timeoutUrl, method, timeout } } // 上报两项核心数据 logPackage() { const { url, timeoutUrl, method } = this.config const domComplete = this.getLoadTime() const timeoutRes = this.getTimeoutRes(this.config.timeout) // 上报页面加载时间 this.log(url, { domeComplete }, method) // 上报超时加载的资源列表 if (timeoutRes.length) { this.log(timeoutUrl, { timeoutRes }, method) } } // 上报数据 log(url, data = {}, type = 'POST') { const method = type.toLowerCase() const urlToUse = method === 'get' ? `${url}?${this.makeItStr(data)}` : url const body = method === 'get' ? {} : { body: this.convert2FormData(data) } // 接口,可用本身项目封装的axios const init = { method, ...body } // 请求接口上报服务器 fetch(urlToUse, init).catch(e => console.log(e)) } getTimeoutRes(limit = this.TIMEOUT) { const isTimeout = this.setTime(limit) // 获取资源加载时间 const resourceTimes = performance.getEntriesByType('resource') // 生成超时资源列表 return resourceTimes.filter(item => isTimeout(this.getDomLoadTime(item))).map(getName) } getDomLoadTime() { // 获取页面加载时间 const [{ domComplete }] = performance.getEntriesByType('navigation') return domComplete } setTime(limit = this.TIMEOUT) { time => time >= limit } getLoadTime({ startTime, responseEnd }) { return responseEnd - startTime } getName({ name }) { return name } // 生成表单数据 convert2FormData(data = {}) { Object.entries(data).reduce((last, [key, value]) => { if (Array.isArray(value)) { return value.reduce((lastResult, item) => { lastResult.append(`${key}[]`, item) return lastResult }, last) } last.append(key, value) return last }, new FormData()) } // 拼接 GET 时的url makeItStr(data = {}) { Object.entries(data) .map(([k, v]) => `${k}=${v}`) .join('&') } }
为了监测工具不占用主线程的 JavaScript 解析时间。所以,最好在页面触发 onload
事件后,采用异步加载的方式:axios
// 在项目的入口文件的底部,js按流程解析 const log = async () => { const PM = await import('/src/utils/PerformanceMonitor.js') PM.init({ url: 'xxx', timeoutUrl: 'xxxx' }) PM.logPackage() } const oldOnload = window.onload window.onload = e => { if (oldOnload && typeof oldOnload === 'string') { oldOnload(e) } // 尽可能不影响页面主线程 if (window.requestIdleCallback) { window.requestIdleCallback(log) } else { setTimeout(log) } }