暗黑主题修复

This commit is contained in:
Alex Yang
2026-01-29 18:57:20 +08:00
parent 00f635ebec
commit ed686b21bb
7 changed files with 1668 additions and 404 deletions

392
static/js/memory-manager.js Normal file
View File

@@ -0,0 +1,392 @@
// memory-manager.js - 全局内存管理模块
// 全局内存管理对象
const memoryManager = {
// 缓存管理
caches: {
ipGeolocation: {
data: new Map(),
maxSize: 1000,
order: []
},
domainInfo: {
data: new Map(),
maxSize: 500
},
apiResponses: {
data: new Map(),
maxSize: 100,
ttl: 60000 // 1分钟过期
}
},
// 资源管理
resources: {
timers: [],
eventListeners: [],
webSockets: [],
intervals: []
},
// 内存监控
monitoring: {
enabled: true,
history: [],
maxHistory: 50,
threshold: 80 // 内存使用阈值(%
},
// 初始化
init() {
console.log('内存管理器初始化');
this.startMonitoring();
this.setupGlobalListeners();
},
// 启动内存监控
startMonitoring() {
if (this.monitoring.enabled && performance && performance.memory) {
setInterval(() => {
this.checkMemoryUsage();
}, 30000); // 每30秒检查一次
}
},
// 检查内存使用情况
checkMemoryUsage() {
if (!performance || !performance.memory) return;
const memory = performance.memory;
const usage = {
timestamp: Date.now(),
used: Math.round(memory.usedJSHeapSize / 1024 / 1024 * 100) / 100, // MB
total: Math.round(memory.totalJSHeapSize / 1024 / 1024 * 100) / 100, // MB
limit: Math.round(memory.jsHeapSizeLimit / 1024 / 1024 * 100) / 100, // MB
usagePercent: Math.round((memory.usedJSHeapSize / memory.jsHeapSizeLimit) * 100 * 100) / 100 // %
};
this.monitoring.history.push(usage);
// 限制历史记录大小
if (this.monitoring.history.length > this.monitoring.maxHistory) {
this.monitoring.history.shift();
}
// 内存使用过高时的处理
if (usage.usagePercent > this.monitoring.threshold) {
console.warn('内存使用过高:', usage);
this.triggerMemoryCleanup();
}
console.log('内存使用情况:', usage);
},
// 触发内存清理
triggerMemoryCleanup() {
console.log('触发内存清理...');
// 清理缓存
this.cleanupCaches();
// 清理未使用的资源
this.cleanupUnusedResources();
},
// 清理缓存
cleanupCaches() {
// 清理IP地理位置缓存
this.cleanupCache('ipGeolocation');
// 清理域名信息缓存
this.cleanupCache('domainInfo');
// 清理API响应缓存
this.cleanupCache('apiResponses');
},
// 清理特定缓存
cleanupCache(cacheName) {
const cache = this.caches[cacheName];
if (!cache) return;
console.log(`清理${cacheName}缓存 - 当前大小: ${cache.data.size}`);
// 清理超出大小限制的缓存
if (cache.data.size > cache.maxSize) {
if (cache.order && cache.order.length > 0) {
// 使用LRU策略
while (cache.data.size > cache.maxSize && cache.order.length > 0) {
const oldestKey = cache.order.shift();
if (oldestKey) {
cache.data.delete(oldestKey);
}
}
} else {
// 简单清理适用于有TTL的缓存
const now = Date.now();
for (const [key, value] of cache.data.entries()) {
if (cache.data.size <= cache.maxSize) break;
// 检查TTL
if (cache.ttl && value.timestamp && (now - value.timestamp) > cache.ttl) {
cache.data.delete(key);
}
}
// 如果仍然超出大小限制,删除最旧的项
if (cache.data.size > cache.maxSize) {
const keys = Array.from(cache.data.keys());
while (cache.data.size > cache.maxSize && keys.length > 0) {
const oldestKey = keys.shift();
cache.data.delete(oldestKey);
}
}
}
}
console.log(`清理后${cacheName}缓存大小: ${cache.data.size}`);
},
// 清理未使用的资源
cleanupUnusedResources() {
// 清理定时器(这里主要是记录,实际清理需要在具体组件中进行)
console.log(`当前活动定时器数量: ${this.resources.timers.length}`);
console.log(`当前活动事件监听器数量: ${this.resources.eventListeners.length}`);
console.log(`当前活动WebSocket连接数量: ${this.resources.webSockets.length}`);
console.log(`当前活动间隔定时器数量: ${this.resources.intervals.length}`);
},
// 添加缓存项
addCacheItem(cacheName, key, value) {
const cache = this.caches[cacheName];
if (!cache) return;
// 检查缓存大小
if (cache.data.size >= cache.maxSize) {
this.cleanupCache(cacheName);
}
// 添加到缓存
if (cache.ttl) {
cache.data.set(key, {
value,
timestamp: Date.now()
});
} else {
cache.data.set(key, value);
}
// 更新访问顺序用于LRU
if (cache.order) {
// 移除现有的位置
const index = cache.order.indexOf(key);
if (index > -1) {
cache.order.splice(index, 1);
}
// 添加到末尾
cache.order.push(key);
}
},
// 获取缓存项
getCacheItem(cacheName, key) {
const cache = this.caches[cacheName];
if (!cache) return null;
const item = cache.data.get(key);
if (!item) return null;
// 检查TTL
if (cache.ttl && item.timestamp && (Date.now() - item.timestamp) > cache.ttl) {
cache.data.delete(key);
return null;
}
// 更新访问顺序用于LRU
if (cache.order) {
// 移除现有的位置
const index = cache.order.indexOf(key);
if (index > -1) {
cache.order.splice(index, 1);
}
// 添加到末尾
cache.order.push(key);
}
return cache.ttl ? item.value : item;
},
// 注册定时器
registerTimer(timerId) {
if (timerId) {
this.resources.timers.push(timerId);
}
},
// 注销定时器
unregisterTimer(timerId) {
const index = this.resources.timers.indexOf(timerId);
if (index > -1) {
clearTimeout(timerId);
this.resources.timers.splice(index, 1);
}
},
// 注册事件监听器
registerEventListener(element, event, handler) {
if (element && event && handler) {
this.resources.eventListeners.push({ element, event, handler });
}
},
// 注销事件监听器
unregisterEventListener(element, event, handler) {
const index = this.resources.eventListeners.findIndex(item =>
item.element === element && item.event === event && item.handler === handler
);
if (index > -1) {
element.removeEventListener(event, handler);
this.resources.eventListeners.splice(index, 1);
}
},
// 注册WebSocket连接
registerWebSocket(ws) {
if (ws) {
this.resources.webSockets.push(ws);
}
},
// 注销WebSocket连接
unregisterWebSocket(ws) {
const index = this.resources.webSockets.indexOf(ws);
if (index > -1) {
try {
ws.close();
} catch (error) {
console.error('关闭WebSocket连接失败:', error);
}
this.resources.webSockets.splice(index, 1);
}
},
// 注册间隔定时器
registerInterval(intervalId) {
if (intervalId) {
this.resources.intervals.push(intervalId);
}
},
// 注销间隔定时器
unregisterInterval(intervalId) {
const index = this.resources.intervals.indexOf(intervalId);
if (index > -1) {
clearInterval(intervalId);
this.resources.intervals.splice(index, 1);
}
},
// 清理所有资源
cleanupAllResources() {
console.log('清理所有资源...');
// 清理定时器
this.resources.timers.forEach(timerId => {
clearTimeout(timerId);
});
this.resources.timers = [];
// 清理事件监听器
this.resources.eventListeners.forEach(({ element, event, handler }) => {
try {
element.removeEventListener(event, handler);
} catch (error) {
console.error('移除事件监听器失败:', error);
}
});
this.resources.eventListeners = [];
// 清理WebSocket连接
this.resources.webSockets.forEach(ws => {
try {
ws.close();
} catch (error) {
console.error('关闭WebSocket连接失败:', error);
}
});
this.resources.webSockets = [];
// 清理间隔定时器
this.resources.intervals.forEach(intervalId => {
clearInterval(intervalId);
});
this.resources.intervals = [];
// 清理缓存
this.cleanupCaches();
console.log('所有资源已清理');
},
// 设置全局监听器
setupGlobalListeners() {
// 页面卸载时清理所有资源
window.addEventListener('beforeunload', () => {
this.cleanupAllResources();
});
// 页面可见性变化时的处理
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
// 页面隐藏时清理一些资源
console.log('页面隐藏,清理资源...');
this.cleanupCaches();
}
});
},
// 获取内存使用统计
getStats() {
if (this.monitoring.history.length === 0) {
return null;
}
const recent = this.monitoring.history[this.monitoring.history.length - 1];
const avg = this.monitoring.history.reduce((sum, item) => sum + item.used, 0) / this.monitoring.history.length;
const max = Math.max(...this.monitoring.history.map(item => item.used));
const min = Math.min(...this.monitoring.history.map(item => item.used));
return {
recent,
avg: Math.round(avg * 100) / 100,
max: Math.round(max * 100) / 100,
min: Math.round(min * 100) / 100,
history: this.monitoring.history,
caches: {
ipGeolocation: this.caches.ipGeolocation.data.size,
domainInfo: this.caches.domainInfo.data.size,
apiResponses: this.caches.apiResponses.data.size
},
resources: {
timers: this.resources.timers.length,
eventListeners: this.resources.eventListeners.length,
webSockets: this.resources.webSockets.length,
intervals: this.resources.intervals.length
}
};
}
};
// 导出内存管理器
if (typeof module !== 'undefined' && module.exports) {
module.exports = memoryManager;
} else {
window.memoryManager = memoryManager;
}
// 自动初始化
if (typeof window !== 'undefined') {
window.addEventListener('DOMContentLoaded', () => {
memoryManager.init();
});
}