my-performance-sdk
Version:
前端性能监控SDK,支持FCP、LCP、TBT、TTI和内存泄漏监控
781 lines (772 loc) • 22 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
/**
* 获取内存使用信息
*/
function getMemoryInfo() {
if ('memory' in performance) {
const memory = performance.memory;
return {
usedJSHeapSize: memory.usedJSHeapSize,
jsHeapSizeLimit: memory.jsHeapSizeLimit,
totalJSHeapSize: memory.totalJSHeapSize
};
}
return null;
}
/**
* 获取页面加载时间
*/
function getLoadTime() {
const navigation = performance.getEntriesByType('navigation')[0];
if (navigation) {
return navigation.loadEventEnd - navigation.loadEventStart;
}
return 0;
}
/**
* 获取DOM内容加载时间
*/
function getDOMContentLoadedTime() {
const navigation = performance.getEntriesByType('navigation')[0];
if (navigation) {
return navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart;
}
return 0;
}
/**
* 计算总阻塞时间 (TBT)
*/
function calculateTBT() {
const longTasks = performance.getEntriesByType('longtask');
let totalBlockingTime = 0;
longTasks.forEach(task => {
const longTask = task;
// 只计算超过50ms的任务
if (longTask.duration > 50) {
totalBlockingTime += longTask.duration - 50;
}
});
return totalBlockingTime;
}
/**
* 计算可交互时间 (TTI)
*/
function calculateTTI() {
const navigation = performance.getEntriesByType('navigation')[0];
if (!navigation)
return 0;
// 简化的TTI计算:DOM内容加载完成时间 + 总阻塞时间
const domContentLoaded = navigation.domContentLoadedEventEnd;
const tbt = calculateTBT();
return domContentLoaded + tbt;
}
/**
* 获取Web Vitals指标
*/
function getWebVitals() {
const vitals = {};
// 获取FCP
const fcpEntry = performance.getEntriesByName('first-contentful-paint')[0];
if (fcpEntry) {
vitals.fcp = fcpEntry.startTime;
}
// 获取LCP
const lcpEntries = performance.getEntriesByType('largest-contentful-paint');
if (lcpEntries.length > 0) {
const lastLCP = lcpEntries[lcpEntries.length - 1];
vitals.lcp = lastLCP.startTime;
}
// 计算TBT
vitals.tbt = calculateTBT();
// 计算TTI
vitals.tti = calculateTTI();
return vitals;
}
/**
* 获取完整的性能指标
*/
function getPerformanceMetrics$1() {
const metrics = {};
// 获取Web Vitals
const vitals = getWebVitals();
metrics.fcp = vitals.fcp;
metrics.lcp = vitals.lcp;
metrics.tbt = vitals.tbt;
metrics.tti = vitals.tti;
// 获取内存信息
const memory = getMemoryInfo();
if (memory) {
metrics.memory = memory;
}
// 获取页面加载时间
metrics.loadTime = getLoadTime();
metrics.domContentLoaded = getDOMContentLoadedTime();
return metrics;
}
/**
* 内存泄漏检测器
*/
class MemoryLeakDetector {
constructor(onLeakDetected) {
this.memoryHistory = [];
this.maxHistoryLength = 50;
this.detectionInterval = null;
this.onLeakDetected = onLeakDetected;
}
/**
* 开始内存泄漏检测
*/
start(intervalMs = 5000) {
if (this.detectionInterval) {
this.stop();
}
this.detectionInterval = window.setInterval(() => {
this.checkMemoryLeak();
}, intervalMs);
}
/**
* 停止内存泄漏检测
*/
stop() {
if (this.detectionInterval) {
clearInterval(this.detectionInterval);
this.detectionInterval = null;
}
}
/**
* 检查内存泄漏
*/
checkMemoryLeak() {
var _a;
const currentMemory = this.getMemoryInfo();
if (!currentMemory)
return;
this.memoryHistory.push(currentMemory);
// 保持历史记录长度
if (this.memoryHistory.length > this.maxHistoryLength) {
this.memoryHistory.shift();
}
// 计算内存增长趋势
if (this.memoryHistory.length >= 10) {
const trend = this.calculateMemoryTrend();
// 如果内存持续增长且增长幅度超过阈值,认为可能存在内存泄漏
if (trend > 0.1) { // 10%的增长阈值
(_a = this.onLeakDetected) === null || _a === void 0 ? void 0 : _a.call(this, {
current: currentMemory,
trend: trend
});
}
}
}
/**
* 计算内存增长趋势
*/
calculateMemoryTrend() {
if (this.memoryHistory.length < 10)
return 0;
const recent = this.memoryHistory.slice(-10);
const older = this.memoryHistory.slice(-20, -10);
if (older.length === 0)
return 0;
const recentAvg = recent.reduce((sum, mem) => sum + mem.usedJSHeapSize, 0) / recent.length;
const olderAvg = older.reduce((sum, mem) => sum + mem.usedJSHeapSize, 0) / older.length;
return (recentAvg - olderAvg) / olderAvg;
}
/**
* 获取当前内存信息
*/
getMemoryInfo() {
if ('memory' in performance) {
const memory = performance.memory;
return {
usedJSHeapSize: memory.usedJSHeapSize,
jsHeapSizeLimit: memory.jsHeapSizeLimit,
totalJSHeapSize: memory.totalJSHeapSize
};
}
return null;
}
/**
* 获取内存历史记录
*/
getMemoryHistory() {
return [...this.memoryHistory];
}
/**
* 清理历史记录
*/
clearHistory() {
this.memoryHistory = [];
}
}
/**
* 数据上报器
*/
class PerformanceReporter {
constructor(reportUrl, reportInterval = 30000) {
this.intervalId = null;
this.dataQueue = [];
this.reportUrl = reportUrl;
this.reportInterval = reportInterval;
}
/**
* 开始定期上报
*/
start() {
if (this.intervalId) {
this.stop();
}
this.intervalId = window.setInterval(() => {
this.report();
}, this.reportInterval);
}
/**
* 停止定期上报
*/
stop() {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
}
/**
* 添加数据到队列
*/
addData(data) {
this.dataQueue.push({
...data,
timestamp: Date.now(),
url: window.location.href,
userAgent: navigator.userAgent
});
}
/**
* 立即上报数据
*/
async report() {
if (this.dataQueue.length === 0)
return;
const dataToReport = [...this.dataQueue];
this.dataQueue = [];
if (this.reportUrl) {
try {
await this.sendData(dataToReport);
}
catch (error) {
console.warn('Performance data report failed:', error);
// 失败时重新加入队列
this.dataQueue.unshift(...dataToReport);
}
}
else {
// 如果没有配置上报URL,则输出到控制台
console.log('Performance Metrics:', dataToReport);
}
}
/**
* 发送数据到服务器
*/
async sendData(data) {
if (!this.reportUrl)
return;
const response = await fetch(this.reportUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
timestamp: Date.now(),
data: data,
sessionId: this.getSessionId()
})
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
}
/**
* 获取会话ID
*/
getSessionId() {
let sessionId = sessionStorage.getItem('performance_sdk_session_id');
if (!sessionId) {
sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
sessionStorage.setItem('performance_sdk_session_id', sessionId);
}
return sessionId;
}
/**
* 获取队列中的数据数量
*/
getQueueSize() {
return this.dataQueue.length;
}
/**
* 清空数据队列
*/
clearQueue() {
this.dataQueue = [];
}
}
/**
* 能耗监控器
*/
class PowerMonitor {
constructor(onPowerChange) {
this.batteryManager = null;
this.cpuUsageHistory = [];
this.maxHistoryLength = 10;
this.monitoringInterval = null;
this.onPowerChange = onPowerChange;
this.initBatteryManager();
}
/**
* 初始化电池管理器
*/
async initBatteryManager() {
if ('getBattery' in navigator) {
try {
this.batteryManager = await navigator.getBattery();
this.setupBatteryListeners();
}
catch (error) {
console.warn('Battery API not supported:', error);
}
}
}
/**
* 设置电池状态监听器
*/
setupBatteryListeners() {
if (!this.batteryManager)
return;
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(intervalMs = 5000) {
if (this.monitoringInterval) {
this.stop();
}
this.monitoringInterval = window.setInterval(() => {
this.collectPowerInfo();
}, intervalMs);
// 立即收集一次数据
this.collectPowerInfo();
}
/**
* 停止能耗监控
*/
stop() {
if (this.monitoringInterval) {
clearInterval(this.monitoringInterval);
this.monitoringInterval = null;
}
}
/**
* 收集能耗信息
*/
collectPowerInfo() {
var _a;
const powerInfo = this.getPowerConsumptionInfo();
(_a = this.onPowerChange) === null || _a === void 0 ? void 0 : _a.call(this, powerInfo);
}
/**
* 获取能耗信息
*/
getPowerConsumptionInfo() {
const info = {
powerLevel: 'medium',
powerScore: 50
};
// 获取电池信息
if (this.batteryManager) {
info.batteryLevel = this.batteryManager.level;
info.charging = this.batteryManager.charging;
info.timeToEmpty = this.batteryManager.dischargingTime;
info.timeToFull = this.batteryManager.chargingTime;
}
// 估算CPU使用率
info.cpuUsage = this.estimateCPUUsage();
// 计算能耗等级和评分
const { powerLevel, powerScore } = this.calculatePowerMetrics(info);
info.powerLevel = powerLevel;
info.powerScore = powerScore;
return info;
}
/**
* 估算CPU使用率
*/
estimateCPUUsage() {
// 基于内存使用率和页面活动来估算CPU使用率
const memory = performance.memory;
if (memory) {
const memoryUsage = memory.usedJSHeapSize / memory.jsHeapSizeLimit;
// 基于内存使用率估算CPU使用率
let cpuUsage = memoryUsage * 100;
// 考虑页面活动
const now = performance.now();
const timeSinceLastActivity = now - this.lastActivityTime || 0;
if (timeSinceLastActivity < 1000) {
cpuUsage += 20; // 最近有活动,增加CPU使用率
}
this.lastActivityTime = now;
return Math.min(cpuUsage, 100);
}
return 0;
}
/**
* 计算能耗指标
*/
calculatePowerMetrics(info) {
let score = 50; // 基础分数
// 基于电池电量调整分数
if (info.batteryLevel !== undefined) {
if (info.batteryLevel < 0.2) {
score += 30; // 电量低,能耗高
}
else if (info.batteryLevel < 0.5) {
score += 15;
}
else {
score -= 10; // 电量充足,能耗相对较低
}
}
// 基于充电状态调整分数
if (info.charging) {
score -= 20; // 充电时能耗相对较低
}
else {
score += 10; // 使用电池时能耗较高
}
// 基于CPU使用率调整分数
if (info.cpuUsage !== undefined) {
if (info.cpuUsage > 80) {
score += 25; // CPU使用率高,能耗高
}
else if (info.cpuUsage > 50) {
score += 10;
}
else {
score -= 5; // CPU使用率低,能耗低
}
}
// 确保分数在0-100范围内
score = Math.max(0, Math.min(100, score));
// 确定能耗等级
let powerLevel;
if (score < 30) {
powerLevel = 'low';
}
else if (score < 70) {
powerLevel = 'medium';
}
else {
powerLevel = 'high';
}
return { powerLevel, powerScore: score };
}
/**
* 获取CPU使用率历史
*/
getCPUUsageHistory() {
return [...this.cpuUsageHistory];
}
/**
* 清理历史数据
*/
clearHistory() {
this.cpuUsageHistory = [];
}
/**
* 检查是否支持能耗监控
*/
isSupported() {
return 'getBattery' in navigator || 'memory' in performance;
}
}
/**
* 前端性能监控SDK
* 支持监控FCP、LCP、TBT、TTI和内存泄漏
*/
class PerformanceSDK {
constructor(options = {}) {
this.isStarted = false;
this.observers = [];
this.options = {
autoStart: true,
enableMemoryMonitoring: true,
enableWebVitals: true,
enablePowerMonitoring: true,
reportInterval: 30000,
...options
};
// 初始化内存泄漏检测器
this.memoryLeakDetector = new MemoryLeakDetector((leakInfo) => {
console.warn('Memory leak detected:', leakInfo);
this.handleMemoryLeak(leakInfo);
});
// 初始化数据上报器
this.reporter = new PerformanceReporter(this.options.reportUrl, this.options.reportInterval);
// 初始化能耗监控器
this.powerMonitor = new PowerMonitor((powerInfo) => {
console.log('Power consumption info:', powerInfo);
this.handlePowerChange(powerInfo);
});
// 如果配置了自动开始,则启动监控
if (this.options.autoStart) {
this.start();
}
}
/**
* 开始性能监控
*/
start() {
if (this.isStarted) {
console.warn('PerformanceSDK is already started');
return;
}
this.isStarted = true;
console.log('PerformanceSDK started');
// 启动数据上报
this.reporter.start();
// 启动内存泄漏检测
if (this.options.enableMemoryMonitoring) {
this.memoryLeakDetector.start();
}
// 启动能耗监控
if (this.options.enablePowerMonitoring) {
this.powerMonitor.start();
}
// 设置性能指标监听
if (this.options.enableWebVitals) {
this.setupPerformanceObservers();
}
// 页面加载完成后获取初始指标
if (document.readyState === 'complete') {
this.collectAndReport();
}
else {
window.addEventListener('load', () => {
this.collectAndReport();
});
}
}
/**
* 停止性能监控
*/
stop() {
if (!this.isStarted) {
console.warn('PerformanceSDK is not started');
return;
}
this.isStarted = false;
console.log('PerformanceSDK stopped');
// 停止数据上报
this.reporter.stop();
// 停止内存泄漏检测
this.memoryLeakDetector.stop();
// 停止能耗监控
this.powerMonitor.stop();
// 清理观察器
this.observers.forEach(observer => observer.disconnect());
this.observers = [];
}
/**
* 获取当前性能指标
*/
getMetrics() {
return getPerformanceMetrics$1();
}
/**
* 手动收集并上报数据
*/
collectAndReport() {
const metrics = this.getMetrics();
// 调用自定义数据处理函数
if (this.options.onData) {
this.options.onData(metrics);
}
// 添加到上报队列
this.reporter.addData(metrics);
}
/**
* 设置性能指标观察器
*/
setupPerformanceObservers() {
if (!('PerformanceObserver' in window)) {
console.warn('PerformanceObserver not supported');
return;
}
try {
// 监听LCP
const lcpObserver = new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
if (lastEntry) {
this.collectAndReport();
}
});
lcpObserver.observe({ entryTypes: ['largest-contentful-paint'] });
this.observers.push(lcpObserver);
// 监听FCP
const fcpObserver = new PerformanceObserver((list) => {
const entries = list.getEntries();
if (entries.length > 0) {
this.collectAndReport();
}
});
fcpObserver.observe({ entryTypes: ['paint'] });
this.observers.push(fcpObserver);
// 监听长任务
const longTaskObserver = new PerformanceObserver((list) => {
const entries = list.getEntries();
if (entries.length > 0) {
this.collectAndReport();
}
});
longTaskObserver.observe({ entryTypes: ['longtask'] });
this.observers.push(longTaskObserver);
}
catch (error) {
console.warn('Failed to setup performance observers:', error);
}
}
/**
* 处理内存泄漏事件
*/
handleMemoryLeak(leakInfo) {
const metrics = this.getMetrics();
metrics.memory = leakInfo.current;
// 添加内存泄漏标记
const leakData = {
...metrics,
memoryLeak: {
detected: true,
trend: leakInfo.trend,
timestamp: Date.now()
}
};
// 调用自定义数据处理函数
if (this.options.onData) {
this.options.onData(leakData);
}
// 添加到上报队列
this.reporter.addData(leakData);
}
/**
* 处理能耗变化事件
*/
handlePowerChange(powerInfo) {
const metrics = this.getMetrics();
metrics.powerConsumption = powerInfo;
// 调用自定义数据处理函数
if (this.options.onData) {
this.options.onData(metrics);
}
// 添加到上报队列
this.reporter.addData(metrics);
}
/**
* 获取内存历史记录
*/
getMemoryHistory() {
return this.memoryLeakDetector.getMemoryHistory();
}
/**
* 获取上报队列大小
*/
getQueueSize() {
return this.reporter.getQueueSize();
}
/**
* 立即上报数据
*/
async reportNow() {
await this.reporter.report();
}
/**
* 检查是否已启动
*/
isRunning() {
return this.isStarted;
}
/**
* 销毁SDK实例
*/
destroy() {
this.stop();
this.memoryLeakDetector.clearHistory();
this.reporter.clearQueue();
}
}
// 创建全局实例的工厂函数
let globalInstance = null;
/**
* 初始化性能监控SDK
* @param options 配置选项
* @returns SDK实例
*/
function initPerformanceSDK(options = {}) {
if (globalInstance) {
console.warn('PerformanceSDK already initialized');
return globalInstance;
}
globalInstance = new PerformanceSDK(options);
return globalInstance;
}
/**
* 获取全局SDK实例
* @returns SDK实例或null
*/
function getPerformanceSDK() {
return globalInstance;
}
/**
* 销毁全局SDK实例
*/
function destroyPerformanceSDK() {
if (globalInstance) {
globalInstance.destroy();
globalInstance = null;
}
}
/**
* 获取当前性能指标
* @returns 性能指标数据
*/
function getPerformanceMetrics() {
if (globalInstance) {
return globalInstance.getMetrics();
}
return {};
}
/**
* 手动收集并上报数据
*/
function collectAndReport() {
if (globalInstance) {
globalInstance.collectAndReport();
}
}
exports.PerformanceSDK = PerformanceSDK;
exports.collectAndReport = collectAndReport;
exports.default = PerformanceSDK;
exports.destroyPerformanceSDK = destroyPerformanceSDK;
exports.getPerformanceMetrics = getPerformanceMetrics;
exports.getPerformanceSDK = getPerformanceSDK;
exports.initPerformanceSDK = initPerformanceSDK;
//# sourceMappingURL=index.js.map