前端性能監控,設置監控超時的任務,回傳到服務器前端
完整代碼以下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) } }