You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

358 lines
12 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* 性能监控器
* Performance Monitor
*
* 监控和优化JavaScript性能特别是动画和滚动性能
* Monitor and optimize JavaScript performance, especially animations and scrolling
*
* @package Nenghui Energy Theme
* @since 1.0.0
*/
(function() {
'use strict';
// 性能监控器
const PerformanceMonitor = {
metrics: {
animations: [],
scrollEvents: 0,
memoryUsage: [],
renderTime: [],
gsapAnimations: 0,
elementorConflicts: 0
},
observers: {
performance: null,
memory: null,
intersection: null
},
// 初始化
init: function() {
if (this.initialized) return;
this.setupPerformanceObserver();
this.setupMemoryMonitoring();
this.setupAnimationMonitoring();
this.setupScrollOptimization();
this.setupIntersectionObserver();
this.initialized = true;
},
// 设置性能观察器
setupPerformanceObserver: function() {
if (!window.PerformanceObserver) return;
try {
this.observers.performance = new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach(entry => {
if (entry.entryType === 'measure') {
this.metrics.renderTime.push({
name: entry.name,
duration: entry.duration,
timestamp: Date.now()
});
}
});
});
this.observers.performance.observe({ entryTypes: ['measure', 'navigation'] });
} catch (e) {
}
},
// 设置内存监控
setupMemoryMonitoring: function() {
if (!performance.memory) return;
const monitorMemory = () => {
const memory = performance.memory;
this.metrics.memoryUsage.push({
used: memory.usedJSHeapSize,
total: memory.totalJSHeapSize,
limit: memory.jsHeapSizeLimit,
timestamp: Date.now()
});
// 保持最近100条记录
if (this.metrics.memoryUsage.length > 100) {
this.metrics.memoryUsage.shift();
}
// 检查内存泄漏
this.checkMemoryLeaks();
};
// 每30秒监控一次内存
setInterval(monitorMemory, 30000);
monitorMemory(); // 立即执行一次
},
// 设置动画监控
setupAnimationMonitoring: function() {
// 监控GSAP动画
if (window.gsap) {
const originalTo = gsap.to;
const originalFrom = gsap.from;
const originalFromTo = gsap.fromTo;
gsap.to = (...args) => {
this.metrics.gsapAnimations++;
return originalTo.apply(gsap, args);
};
gsap.from = (...args) => {
this.metrics.gsapAnimations++;
return originalFrom.apply(gsap, args);
};
gsap.fromTo = (...args) => {
this.metrics.gsapAnimations++;
return originalFromTo.apply(gsap, args);
};
}
// 监控CSS动画
document.addEventListener('animationstart', (e) => {
this.metrics.animations.push({
type: 'css',
name: e.animationName,
target: e.target.tagName,
timestamp: Date.now()
});
});
},
// 设置滚动优化
setupScrollOptimization: function() {
let scrollTimeout;
let lastScrollTime = 0;
const optimizedScrollHandler = (e) => {
const now = Date.now();
// 限制滚动事件频率
if (now - lastScrollTime < 16) return; // 约60fps
lastScrollTime = now;
this.metrics.scrollEvents++;
// 清除之前的超时
clearTimeout(scrollTimeout);
// 滚动结束后的清理工作
scrollTimeout = setTimeout(() => {
this.optimizeAfterScroll();
}, 150);
};
window.addEventListener('scroll', optimizedScrollHandler, { passive: true });
},
// 设置交叉观察器
setupIntersectionObserver: function() {
if (!window.IntersectionObserver) return;
this.observers.intersection = new IntersectionObserver((entries) => {
entries.forEach(entry => {
const element = entry.target;
if (entry.isIntersecting) {
// 元素进入视口,可以启动动画
element.classList.add('in-viewport');
this.triggerLazyAnimations(element);
} else {
// 元素离开视口,可以暂停动画
element.classList.remove('in-viewport');
this.pauseAnimations(element);
}
});
}, {
rootMargin: '50px',
threshold: 0.1
});
// 观察所有动画元素
document.querySelectorAll('[data-animate], .gsap-animate, .elementor-invisible').forEach(el => {
this.observers.intersection.observe(el);
});
},
// 检查内存泄漏
checkMemoryLeaks: function() {
const recent = this.metrics.memoryUsage.slice(-10);
if (recent.length < 10) return;
const trend = recent.reduce((acc, curr, index) => {
if (index === 0) return acc;
return acc + (curr.used - recent[index - 1].used);
}, 0);
if (trend > 10 * 1024 * 1024) { // 10MB增长
console.warn('⚠️ 检测到潜在内存泄漏,内存使用持续增长');
this.cleanupMemory();
}
},
// 清理内存
cleanupMemory: function() {
// 清理过期的动画记录
const now = Date.now();
this.metrics.animations = this.metrics.animations.filter(anim =>
now - anim.timestamp < 300000 // 保留5分钟内的记录
);
// 清理过期的渲染时间记录
this.metrics.renderTime = this.metrics.renderTime.filter(render =>
now - render.timestamp < 300000
);
// 强制垃圾回收(如果可用)
if (window.gc) {
window.gc();
}
},
// 滚动后优化
optimizeAfterScroll: function() {
// 刷新ScrollTrigger
if (window.ScrollTrigger) {
ScrollTrigger.refresh();
}
// 清理不在视口内的动画
document.querySelectorAll('.gsap-animate:not(.in-viewport)').forEach(el => {
gsap.killTweensOf(el);
});
},
// 触发懒加载动画
triggerLazyAnimations: function(element) {
if (element.hasAttribute('data-lazy-animate')) {
const animationType = element.getAttribute('data-lazy-animate');
switch (animationType) {
case 'fadeIn':
gsap.fromTo(element,
{ opacity: 0, y: 30 },
{ opacity: 1, y: 0, duration: 0.6, ease: "power2.out" }
);
break;
case 'slideIn':
gsap.fromTo(element,
{ x: -50, opacity: 0 },
{ x: 0, opacity: 1, duration: 0.8, ease: "power2.out" }
);
break;
}
element.removeAttribute('data-lazy-animate');
}
},
// 暂停动画
pauseAnimations: function(element) {
if (window.gsap) {
gsap.killTweensOf(element);
}
},
// 获取性能报告
getPerformanceReport: function() {
const memoryUsage = this.metrics.memoryUsage;
const currentMemory = memoryUsage[memoryUsage.length - 1];
return {
summary: {
totalAnimations: this.metrics.animations.length,
gsapAnimations: this.metrics.gsapAnimations,
scrollEvents: this.metrics.scrollEvents,
elementorConflicts: this.metrics.elementorConflicts
},
memory: {
current: currentMemory ? Math.round(currentMemory.used / 1024 / 1024) + 'MB' : 'N/A',
peak: memoryUsage.length > 0 ?
Math.round(Math.max(...memoryUsage.map(m => m.used)) / 1024 / 1024) + 'MB' : 'N/A'
},
performance: {
averageRenderTime: this.metrics.renderTime.length > 0 ?
Math.round(this.metrics.renderTime.reduce((sum, r) => sum + r.duration, 0) / this.metrics.renderTime.length) + 'ms' : 'N/A'
},
recommendations: this.getRecommendations()
};
},
// 获取优化建议
getRecommendations: function() {
const recommendations = [];
if (this.metrics.scrollEvents > 1000) {
recommendations.push('考虑进一步优化滚动事件处理,使用更大的节流间隔');
}
if (this.metrics.gsapAnimations > 50) {
recommendations.push('GSAP动画数量较多考虑使用对象池或动画复用');
}
const memoryUsage = this.metrics.memoryUsage;
if (memoryUsage.length > 0) {
const latest = memoryUsage[memoryUsage.length - 1];
if (latest.used > latest.total * 0.8) {
recommendations.push('内存使用率较高,建议清理未使用的动画和事件监听器');
}
}
return recommendations;
},
// 销毁监控器
destroy: function() {
// 断开所有观察器
Object.values(this.observers).forEach(observer => {
if (observer && observer.disconnect) {
observer.disconnect();
}
});
// 清理数据
this.metrics = {
animations: [],
scrollEvents: 0,
memoryUsage: [],
renderTime: [],
gsapAnimations: 0,
elementorConflicts: 0
};
this.initialized = false;
}
};
// 等待DOM加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => PerformanceMonitor.init());
} else {
PerformanceMonitor.init();
}
// 页面卸载时清理
window.addEventListener('beforeunload', () => PerformanceMonitor.destroy());
// 暴露到全局作用域
window.PerformanceMonitor = PerformanceMonitor;
// 开发模式下的调试功能
if (window.location.hostname === 'localhost' || window.location.search.includes('debug=1')) {
// 每分钟输出性能报告
setInterval(() => {
}, 60000);
// 添加全局调试命令
window.debugPerformance = () => PerformanceMonitor.getPerformanceReport();
}
})();