my-performance-sdk
Version:
前端性能监控SDK,支持FCP、LCP、TBT、TTI和内存泄漏监控
3 lines (2 loc) • 9.14 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).MyPerformanceSDK={})}(this,function(e){"use strict";function t(){const e=performance.getEntriesByType("longtask");let t=0;return e.forEach(e=>{const r=e;r.duration>50&&(t+=r.duration-50)}),t}function r(){const e={},r=performance.getEntriesByName("first-contentful-paint")[0];r&&(e.fcp=r.startTime);const o=performance.getEntriesByType("largest-contentful-paint");if(o.length>0){const t=o[o.length-1];e.lcp=t.startTime}return e.tbt=t(),e.tti=function(){const e=performance.getEntriesByType("navigation")[0];return e?e.domContentLoadedEventEnd+t():0}(),e}function o(){const e={},t=r();e.fcp=t.fcp,e.lcp=t.lcp,e.tbt=t.tbt,e.tti=t.tti;const o=function(){if("memory"in performance){const e=performance.memory;return{usedJSHeapSize:e.usedJSHeapSize,jsHeapSizeLimit:e.jsHeapSizeLimit,totalJSHeapSize:e.totalJSHeapSize}}return null}();return o&&(e.memory=o),e.loadTime=function(){const e=performance.getEntriesByType("navigation")[0];return e?e.loadEventEnd-e.loadEventStart:0}(),e.domContentLoaded=function(){const e=performance.getEntriesByType("navigation")[0];return e?e.domContentLoadedEventEnd-e.domContentLoadedEventStart:0}(),e}class n{constructor(e){this.memoryHistory=[],this.maxHistoryLength=50,this.detectionInterval=null,this.onLeakDetected=e}start(e=5e3){this.detectionInterval&&this.stop(),this.detectionInterval=window.setInterval(()=>{this.checkMemoryLeak()},e)}stop(){this.detectionInterval&&(clearInterval(this.detectionInterval),this.detectionInterval=null)}checkMemoryLeak(){var e;const t=this.getMemoryInfo();if(t&&(this.memoryHistory.push(t),this.memoryHistory.length>this.maxHistoryLength&&this.memoryHistory.shift(),this.memoryHistory.length>=10)){const r=this.calculateMemoryTrend();r>.1&&(null===(e=this.onLeakDetected)||void 0===e||e.call(this,{current:t,trend:r}))}}calculateMemoryTrend(){if(this.memoryHistory.length<10)return 0;const e=this.memoryHistory.slice(-10),t=this.memoryHistory.slice(-20,-10);if(0===t.length)return 0;const r=e.reduce((e,t)=>e+t.usedJSHeapSize,0)/e.length,o=t.reduce((e,t)=>e+t.usedJSHeapSize,0)/t.length;return(r-o)/o}getMemoryInfo(){if("memory"in performance){const e=performance.memory;return{usedJSHeapSize:e.usedJSHeapSize,jsHeapSizeLimit:e.jsHeapSizeLimit,totalJSHeapSize:e.totalJSHeapSize}}return null}getMemoryHistory(){return[...this.memoryHistory]}clearHistory(){this.memoryHistory=[]}}class s{constructor(e,t=3e4){this.intervalId=null,this.dataQueue=[],this.reportUrl=e,this.reportInterval=t}start(){this.intervalId&&this.stop(),this.intervalId=window.setInterval(()=>{this.report()},this.reportInterval)}stop(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null)}addData(e){this.dataQueue.push({...e,timestamp:Date.now(),url:window.location.href,userAgent:navigator.userAgent})}async report(){if(0===this.dataQueue.length)return;const e=[...this.dataQueue];if(this.dataQueue=[],this.reportUrl)try{await this.sendData(e)}catch(t){console.warn("Performance data report failed:",t),this.dataQueue.unshift(...e)}else console.log("Performance Metrics:",e)}async sendData(e){if(!this.reportUrl)return;const t=await fetch(this.reportUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({timestamp:Date.now(),data:e,sessionId:this.getSessionId()})});if(!t.ok)throw new Error(`HTTP ${t.status}: ${t.statusText}`)}getSessionId(){let e=sessionStorage.getItem("performance_sdk_session_id");return e||(e=`session_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,sessionStorage.setItem("performance_sdk_session_id",e)),e}getQueueSize(){return this.dataQueue.length}clearQueue(){this.dataQueue=[]}}class i{constructor(e){this.batteryManager=null,this.cpuUsageHistory=[],this.maxHistoryLength=10,this.monitoringInterval=null,this.onPowerChange=e,this.initBatteryManager()}async initBatteryManager(){if("getBattery"in navigator)try{this.batteryManager=await navigator.getBattery(),this.setupBatteryListeners()}catch(e){console.warn("Battery API not supported:",e)}}setupBatteryListeners(){this.batteryManager&&(this.batteryManager.addEventListener("levelchange",()=>{this.collectPowerInfo()}),this.batteryManager.addEventListener("chargingchange",()=>{this.collectPowerInfo()}),this.batteryManager.addEventListener("chargingtimechange",()=>{this.collectPowerInfo()}),this.batteryManager.addEventListener("dischargingtimechange",()=>{this.collectPowerInfo()}))}start(e=5e3){this.monitoringInterval&&this.stop(),this.monitoringInterval=window.setInterval(()=>{this.collectPowerInfo()},e),this.collectPowerInfo()}stop(){this.monitoringInterval&&(clearInterval(this.monitoringInterval),this.monitoringInterval=null)}collectPowerInfo(){var e;const t=this.getPowerConsumptionInfo();null===(e=this.onPowerChange)||void 0===e||e.call(this,t)}getPowerConsumptionInfo(){const e={powerLevel:"medium",powerScore:50};this.batteryManager&&(e.batteryLevel=this.batteryManager.level,e.charging=this.batteryManager.charging,e.timeToEmpty=this.batteryManager.dischargingTime,e.timeToFull=this.batteryManager.chargingTime),e.cpuUsage=this.estimateCPUUsage();const{powerLevel:t,powerScore:r}=this.calculatePowerMetrics(e);return e.powerLevel=t,e.powerScore=r,e}estimateCPUUsage(){const e=performance.memory;if(e){let t=100*(e.usedJSHeapSize/e.jsHeapSizeLimit);const r=performance.now();return(r-this.lastActivityTime||0)<1e3&&(t+=20),this.lastActivityTime=r,Math.min(t,100)}return 0}calculatePowerMetrics(e){let t,r=50;return void 0!==e.batteryLevel&&(e.batteryLevel<.2?r+=30:e.batteryLevel<.5?r+=15:r-=10),e.charging?r-=20:r+=10,void 0!==e.cpuUsage&&(e.cpuUsage>80?r+=25:e.cpuUsage>50?r+=10:r-=5),r=Math.max(0,Math.min(100,r)),t=r<30?"low":r<70?"medium":"high",{powerLevel:t,powerScore:r}}getCPUUsageHistory(){return[...this.cpuUsageHistory]}clearHistory(){this.cpuUsageHistory=[]}isSupported(){return"getBattery"in navigator||"memory"in performance}}class a{constructor(e={}){this.isStarted=!1,this.observers=[],this.options={autoStart:!0,enableMemoryMonitoring:!0,enableWebVitals:!0,enablePowerMonitoring:!0,reportInterval:3e4,...e},this.memoryLeakDetector=new n(e=>{console.warn("Memory leak detected:",e),this.handleMemoryLeak(e)}),this.reporter=new s(this.options.reportUrl,this.options.reportInterval),this.powerMonitor=new i(e=>{console.log("Power consumption info:",e),this.handlePowerChange(e)}),this.options.autoStart&&this.start()}start(){this.isStarted?console.warn("PerformanceSDK is already started"):(this.isStarted=!0,console.log("PerformanceSDK started"),this.reporter.start(),this.options.enableMemoryMonitoring&&this.memoryLeakDetector.start(),this.options.enablePowerMonitoring&&this.powerMonitor.start(),this.options.enableWebVitals&&this.setupPerformanceObservers(),"complete"===document.readyState?this.collectAndReport():window.addEventListener("load",()=>{this.collectAndReport()}))}stop(){this.isStarted?(this.isStarted=!1,console.log("PerformanceSDK stopped"),this.reporter.stop(),this.memoryLeakDetector.stop(),this.powerMonitor.stop(),this.observers.forEach(e=>e.disconnect()),this.observers=[]):console.warn("PerformanceSDK is not started")}getMetrics(){return o()}collectAndReport(){const e=this.getMetrics();this.options.onData&&this.options.onData(e),this.reporter.addData(e)}setupPerformanceObservers(){if("PerformanceObserver"in window)try{const e=new PerformanceObserver(e=>{const t=e.getEntries();t[t.length-1]&&this.collectAndReport()});e.observe({entryTypes:["largest-contentful-paint"]}),this.observers.push(e);const t=new PerformanceObserver(e=>{e.getEntries().length>0&&this.collectAndReport()});t.observe({entryTypes:["paint"]}),this.observers.push(t);const r=new PerformanceObserver(e=>{e.getEntries().length>0&&this.collectAndReport()});r.observe({entryTypes:["longtask"]}),this.observers.push(r)}catch(e){console.warn("Failed to setup performance observers:",e)}else console.warn("PerformanceObserver not supported")}handleMemoryLeak(e){const t=this.getMetrics();t.memory=e.current;const r={...t,memoryLeak:{detected:!0,trend:e.trend,timestamp:Date.now()}};this.options.onData&&this.options.onData(r),this.reporter.addData(r)}handlePowerChange(e){const t=this.getMetrics();t.powerConsumption=e,this.options.onData&&this.options.onData(t),this.reporter.addData(t)}getMemoryHistory(){return this.memoryLeakDetector.getMemoryHistory()}getQueueSize(){return this.reporter.getQueueSize()}async reportNow(){await this.reporter.report()}isRunning(){return this.isStarted}destroy(){this.stop(),this.memoryLeakDetector.clearHistory(),this.reporter.clearQueue()}}let c=null;e.PerformanceSDK=a,e.collectAndReport=function(){c&&c.collectAndReport()},e.default=a,e.destroyPerformanceSDK=function(){c&&(c.destroy(),c=null)},e.getPerformanceMetrics=function(){return c?c.getMetrics():{}},e.getPerformanceSDK=function(){return c},e.initPerformanceSDK=function(e={}){return c?(console.warn("PerformanceSDK already initialized"),c):(c=new a(e),c)},Object.defineProperty(e,"__esModule",{value:!0})});
//# sourceMappingURL=index.min.js.map