UNPKG

bmfe-monitor

Version:

前端监测平台

232 lines (206 loc) 8.53 kB
// https://developer.mozilla.org/zh-CN/docs/Web/API/PerformanceTiming import Report from './report'; let report = new Report() let cycleFreq = 100; // 循环轮询的时间 let isDOMReady = false; let isOnload = false; let performance = window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance; let timeFlag = null let Util = { addEventListener: function (name, callback, useCapture) { if (window.addEventListener) { return window.addEventListener(name, callback, useCapture); } else if (window.attachEvent) { return window.attachEvent('on' + name, callback); } }, // uninitialized - 还未开始载入 // loading - 载入中 // interactive - 已加载,文档与用户可以开始交互 // complete - 载入完成 domready: function (callback) { if (isOnload === true) { return void 0; } let timer = null; if (document.readyState === 'interactive') { runCheck(); } else if (document.addEventListener) { document.addEventListener('DOMContentLoaded', function () { runCheck(); }, false); } else if (document.attachEvent) { document.attachEvent('onreadystatechange', function () { runCheck(); }); } function runCheck() { if (performance.timing.domInteractive) { clearTimeout(timer); callback(); isDOMReady = true; } else { timer = setTimeout(runCheck, cycleFreq); } } }, onload: function (callback) { let timer = null; if (document.readyState === 'complete') { runCheck(); } else { Util.addEventListener('load', function () { runCheck(); }, false); } function runCheck() { if (performance.timing.loadEventEnd) { clearTimeout(timer); callback(); isOnload = true; } else { timer = setTimeout(runCheck, cycleFreq); } } } }; // 过滤无效数据 function filterTime(a, b) { return (a > 0 && b > 0 && (a - b) >= 0) ? (a - b) : undefined; } function reportPerf(type,detailShow=false) { if (!performance) { return void 0; } // append data from window.performance let timing = performance.timing; let perfData = { // 类型 type, // 网络建连 pervPage: filterTime(timing.fetchStart, timing.navigationStart), // 上一个页面 redirect: filterTime(timing.redirectEnd, timing.redirectStart), // 页面重定向时间 appCache: filterTime(timing.domainLookupStart, timing.fetchStart), // DNS缓存时间 dns: filterTime(timing.domainLookupEnd, timing.domainLookupStart), // DNS查找时间 connect: filterTime(timing.connectEnd, timing.connectStart), // TCP建连时间 network: filterTime(timing.connectEnd, timing.navigationStart), // 网络总耗时 // 网络接收 send: filterTime(timing.responseStart, timing.requestStart), // 从发送到接收到第一个返回 receive: filterTime(timing.responseEnd, timing.responseStart), // 接受页面时间 // 前端渲染 dom: filterTime(timing.domInteractive, timing.domLoading), // dom解析时间 contentLoad: filterTime(timing.domContentLoadedEventEnd, timing.domContentLoadedEventStart), // DOM解析完成后,内置资源加载时间 contentExec: filterTime(timing.domComplete, timing.domContentLoadedEventEnd), // 内置资源执行时间 loadEvent: filterTime(timing.loadEventEnd, timing.loadEventStart), // load执行时间 // 关键阶段 interactive: filterTime(timing.domInteractive, timing.navigationStart), // 可操作时间 ttfb: filterTime(timing.responseStart, timing.navigationStart), // 首字节时间 load: filterTime(timing.loadEventEnd, timing.navigationStart), // 页面完全加载时间 }; if(detailShow) { let detail = { navigationStart: timing.navigationStart, unloadEventStart: timing.unloadEventStart, unloadEventEnd: timing.unloadEventEnd, redirectStart: timing.redirectStart, redirectEnd: timing.redirectEnd, fetchStart: timing.fetchStart, domainLookupStart: timing.domainLookupStart, domainLookupEnd: timing.domainLookupEnd, connectStart: timing.connectStart, connectEnd: timing.connectEnd, secureConnectionStart: timing.secureConnectionStart, requestStart: timing.requestStart, responseStart: timing.responseStart, responseEnd: timing.responseEnd, domLoading: timing.domLoading, domInteractive: timing.domInteractive, domContentLoadedEventStart: timing.domContentLoadedEventStart, domContentLoadedEventEnd: timing.domContentLoadedEventEnd, domComplete: timing.domComplete, loadEventStart: timing.loadEventStart, loadEventEnd: timing.loadEventEnd, } console.table(detail); } return perfData; }; // 获取first-paint及first-contentful-paint的时间 function getPaintTime() { return new Promise((resolve,reject)=>{ if (window.performance && window.performance.getEntriesByType) { getWS(resolve) } else { reject() } }) } function getWS(resolve) { clearTimeout(timeFlag) timeFlag = setTimeout(()=>{ let origin_obj = {} let result_obj = {} let paintArr = window.performance.getEntriesByType('paint') for (const entry of paintArr) { origin_obj[entry.name] = entry.startTime + entry.duration } if (origin_obj['first-paint'] && origin_obj['first-contentful-paint']) { result_obj['fp'] = Math.round(origin_obj['first-paint']) result_obj['fcp'] = Math.round(origin_obj['first-contentful-paint']) result_obj.whiteScreen = Math.round(origin_obj['first-contentful-paint'] - origin_obj['first-paint']) resolve(result_obj) } else { getWS(resolve) } },100) } function showTable(perfData) { // console.groupCollapsed(perfData.type) let data = { '上一个页面': { '时间(ms)': perfData.pervPage }, '页面重定向': { '时间(ms)': perfData.redirect }, 'DNS缓存查找': { '时间(ms)': perfData.appCache }, 'DNS查找': { '时间(ms)': perfData.dns }, 'TCP建连': { '时间(ms)': perfData.connect }, '网络总耗时': { '时间(ms)': perfData.network }, '从发送到接收到第一个返回': { '时间(ms)': perfData.send }, '接收数据时长': { '时间(ms)': perfData.receive }, '接收首字节用时': { '时间(ms)': perfData.ttfb }, 'dom解析': { '时间(ms)': perfData.dom }, '内置资源加载时长': { '时间(ms)': perfData.contentLoad }, '内置资源执行时长': { '时间(ms)': perfData.contentExec }, 'load执行用时': { '时间(ms)': perfData.loadEvent }, '页面完全加载': { '时间(ms)': perfData.load }, '白屏': { '时间(ms)': perfData.whiteScreen }, '可操作': { '时间(ms)': perfData.interactive } } console.table(data); // console.groupEnd(); } let perf = { init: (config, cb) => { // Util.domready(() => { // let perfData = reportPerf('domready'); // cb(perfData); // }); report.init(config) Util.onload(() => { let perfData = reportPerf('onload',config.detailShow); getPaintTime().then((ptData)=>{ perfData = Object.assign({}, perfData, ptData) perfData.timestamp = Date.now() report.send(perfData) if (config.analyzeShow) { showTable(perfData) } cb && cb(perfData); },()=>{ perfData.timestamp = Date.now() report.send(perfData) if (config.analyzeShow) { showTable(perfData) } cb && cb(perfData); }) }); } }; export default perf;