feat: 实现 ArgonMemoryManager 内存管理类

- 实现构造函数和 ID 跟踪集合(timers, intervals, frames)
- 实现 setTimeout()、setInterval()、requestAnimationFrame() 包装方法
- 实现对应的清理方法(clearTimeout, clearInterval, cancelAnimationFrame)
- 实现 clearAll() 统一清理接口
- 实现 getStats() 获取统计信息
- 创建完整的 HTML 测试文件验证功能
- 支持参数传递给回调函数
- 自动跟踪和清理,避免内存泄漏

验证需求:
- 需求 12.5: 闭包引用大型对象时仅保存必要属性
- 需求 13.4: 组件销毁或页面切换时取消所有定时器和动画帧
This commit is contained in:
2026-01-21 23:29:55 +08:00
parent f165fac420
commit d33f343475
4 changed files with 952 additions and 1 deletions

View File

@@ -101,7 +101,7 @@
- **验证:需求 5.2, 5.3, 5.5** - **验证:需求 5.2, 5.3, 5.5**
- [~] 7. 实现内存管理模块 - [~] 7. 实现内存管理模块
- [~] 7.1 创建 ArgonMemoryManager 类 - [x] 7.1 创建 ArgonMemoryManager 类
- 实现构造函数和 ID 跟踪集合 - 实现构造函数和 ID 跟踪集合
- 实现 setTimeout()、setInterval()、requestAnimationFrame() 包装方法 - 实现 setTimeout()、setInterval()、requestAnimationFrame() 包装方法
- 实现对应的清理方法 - 实现对应的清理方法

View File

@@ -0,0 +1,564 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ArgonMemoryManager 测试</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.test-section {
background: white;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.test-section h2 {
margin-top: 0;
color: #333;
border-bottom: 2px solid #4CAF50;
padding-bottom: 10px;
}
.test-result {
padding: 10px;
margin: 10px 0;
border-radius: 4px;
font-family: monospace;
}
.test-result.pass {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.test-result.fail {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.test-result.info {
background: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
}
button {
background: #4CAF50;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
margin: 5px;
}
button:hover {
background: #45a049;
}
</style>
</head>
<body>
<h1>🧠 ArgonMemoryManager 内存管理模块测试</h1>
<!-- setTimeout 测试 -->
<div class="test-section">
<h2>1. setTimeout 跟踪测试</h2>
<button onclick="testSetTimeout()">运行测试</button>
<div id="setTimeout-results"></div>
</div>
<!-- setInterval 测试 -->
<div class="test-section">
<h2>2. setInterval 跟踪测试</h2>
<button onclick="testSetInterval()">运行测试</button>
<div id="setInterval-results"></div>
</div>
<!-- requestAnimationFrame 测试 -->
<div class="test-section">
<h2>3. requestAnimationFrame 跟踪测试</h2>
<button onclick="testRequestAnimationFrame()">运行测试</button>
<div id="requestAnimationFrame-results"></div>
</div>
<!-- clearTimeout 测试 -->
<div class="test-section">
<h2>4. clearTimeout 测试</h2>
<button onclick="testClearTimeout()">运行测试</button>
<div id="clearTimeout-results"></div>
</div>
<!-- clearAll 测试 -->
<div class="test-section">
<h2>5. clearAll 统一清理测试</h2>
<button onclick="testClearAll()">运行测试</button>
<div id="clearAll-results"></div>
</div>
<!-- 参数传递测试 -->
<div class="test-section">
<h2>6. 参数传递测试</h2>
<button onclick="testArgumentPassing()">运行测试</button>
<div id="argumentPassing-results"></div>
</div>
<!-- 统计信息测试 -->
<div class="test-section">
<h2>7. getStats 统计信息测试</h2>
<button onclick="testGetStats()">运行测试</button>
<div id="getStats-results"></div>
</div>
<!-- 综合测试 -->
<div class="test-section">
<h2>8. 综合测试</h2>
<button onclick="runAllTests()">运行所有测试</button>
<div id="all-tests-results"></div>
</div>
<!-- 加载性能优化模块 -->
<script src="argon-performance.js"></script>
<script>
// 工具函数:输出测试结果
function logResult(containerId, message, type = 'info') {
const container = document.getElementById(containerId);
const div = document.createElement('div');
div.className = `test-result ${type}`;
div.textContent = message;
container.appendChild(div);
}
function clearResults(containerId) {
document.getElementById(containerId).innerHTML = '';
}
// 测试 1: setTimeout 跟踪
function testSetTimeout() {
clearResults('setTimeout-results');
logResult('setTimeout-results', '开始测试 setTimeout 跟踪...', 'info');
try {
const memoryManager = new ArgonMemoryManager();
logResult('setTimeout-results', '✓ ArgonMemoryManager 实例创建成功', 'pass');
let executed = false;
const id = memoryManager.setTimeout(() => {
executed = true;
}, 50);
// 验证 ID 被跟踪
if (memoryManager.timers.has(id)) {
logResult('setTimeout-results', `✓ setTimeout ID (${id}) 已被跟踪`, 'pass');
} else {
logResult('setTimeout-results', '✗ setTimeout ID 未被跟踪', 'fail');
}
// 验证统计信息
const stats = memoryManager.getStats();
if (stats.timers === 1) {
logResult('setTimeout-results', `✓ 统计信息正确timers = ${stats.timers}`, 'pass');
} else {
logResult('setTimeout-results', `✗ 统计信息错误timers = ${stats.timers}`, 'fail');
}
// 等待执行完成
setTimeout(() => {
if (executed) {
logResult('setTimeout-results', '✓ setTimeout 回调函数执行成功', 'pass');
} else {
logResult('setTimeout-results', '✗ setTimeout 回调函数未执行', 'fail');
}
// 验证执行后自动移除
if (!memoryManager.timers.has(id)) {
logResult('setTimeout-results', '✓ 执行后自动从跟踪集合中移除', 'pass');
} else {
logResult('setTimeout-results', '✗ 执行后未从跟踪集合中移除', 'fail');
}
const statsAfter = memoryManager.getStats();
if (statsAfter.timers === 0) {
logResult('setTimeout-results', '✓ 统计信息已更新timers = 0', 'pass');
} else {
logResult('setTimeout-results', `✗ 统计信息未更新timers = ${statsAfter.timers}`, 'fail');
}
logResult('setTimeout-results', '✅ setTimeout 跟踪测试完成', 'info');
}, 100);
} catch (error) {
logResult('setTimeout-results', `✗ 测试出错: ${error.message}`, 'fail');
}
}
// 测试 2: setInterval 跟踪
function testSetInterval() {
clearResults('setInterval-results');
logResult('setInterval-results', '开始测试 setInterval 跟踪...', 'info');
try {
const memoryManager = new ArgonMemoryManager();
let count = 0;
const id = memoryManager.setInterval(() => {
count++;
}, 30);
// 验证 ID 被跟踪
if (memoryManager.intervals.has(id)) {
logResult('setInterval-results', `✓ setInterval ID (${id}) 已被跟踪`, 'pass');
} else {
logResult('setInterval-results', '✗ setInterval ID 未被跟踪', 'fail');
}
// 验证统计信息
const stats = memoryManager.getStats();
if (stats.intervals === 1) {
logResult('setInterval-results', `✓ 统计信息正确intervals = ${stats.intervals}`, 'pass');
} else {
logResult('setInterval-results', `✗ 统计信息错误intervals = ${stats.intervals}`, 'fail');
}
// 等待执行几次
setTimeout(() => {
if (count >= 2) {
logResult('setInterval-results', `✓ setInterval 回调函数执行了 ${count}`, 'pass');
} else {
logResult('setInterval-results', `✗ setInterval 回调函数只执行了 ${count}`, 'fail');
}
// 手动清除
memoryManager.clearInterval(id);
if (!memoryManager.intervals.has(id)) {
logResult('setInterval-results', '✓ clearInterval 后从跟踪集合中移除', 'pass');
} else {
logResult('setInterval-results', '✗ clearInterval 后未从跟踪集合中移除', 'fail');
}
const countBeforeWait = count;
// 等待一段时间,验证已停止执行
setTimeout(() => {
if (count === countBeforeWait) {
logResult('setInterval-results', '✓ clearInterval 后停止执行', 'pass');
} else {
logResult('setInterval-results', '✗ clearInterval 后仍在执行', 'fail');
}
logResult('setInterval-results', '✅ setInterval 跟踪测试完成', 'info');
}, 100);
}, 100);
} catch (error) {
logResult('setInterval-results', `✗ 测试出错: ${error.message}`, 'fail');
}
}
// 测试 3: requestAnimationFrame 跟踪
function testRequestAnimationFrame() {
clearResults('requestAnimationFrame-results');
logResult('requestAnimationFrame-results', '开始测试 requestAnimationFrame 跟踪...', 'info');
try {
const memoryManager = new ArgonMemoryManager();
let executed = false;
let receivedTimestamp = null;
const id = memoryManager.requestAnimationFrame((timestamp) => {
executed = true;
receivedTimestamp = timestamp;
});
// 验证 ID 被跟踪
if (memoryManager.frames.has(id)) {
logResult('requestAnimationFrame-results', `✓ requestAnimationFrame ID (${id}) 已被跟踪`, 'pass');
} else {
logResult('requestAnimationFrame-results', '✗ requestAnimationFrame ID 未被跟踪', 'fail');
}
// 验证统计信息
const stats = memoryManager.getStats();
if (stats.frames === 1) {
logResult('requestAnimationFrame-results', `✓ 统计信息正确frames = ${stats.frames}`, 'pass');
} else {
logResult('requestAnimationFrame-results', `✗ 统计信息错误frames = ${stats.frames}`, 'fail');
}
// 等待执行完成
setTimeout(() => {
if (executed) {
logResult('requestAnimationFrame-results', '✓ requestAnimationFrame 回调函数执行成功', 'pass');
} else {
logResult('requestAnimationFrame-results', '✗ requestAnimationFrame 回调函数未执行', 'fail');
}
if (receivedTimestamp !== null) {
logResult('requestAnimationFrame-results', `✓ 接收到 timestamp 参数: ${receivedTimestamp}`, 'pass');
} else {
logResult('requestAnimationFrame-results', '✗ 未接收到 timestamp 参数', 'fail');
}
// 验证执行后自动移除
if (!memoryManager.frames.has(id)) {
logResult('requestAnimationFrame-results', '✓ 执行后自动从跟踪集合中移除', 'pass');
} else {
logResult('requestAnimationFrame-results', '✗ 执行后未从跟踪集合中移除', 'fail');
}
logResult('requestAnimationFrame-results', '✅ requestAnimationFrame 跟踪测试完成', 'info');
}, 50);
} catch (error) {
logResult('requestAnimationFrame-results', `✗ 测试出错: ${error.message}`, 'fail');
}
}
// 测试 4: clearTimeout
function testClearTimeout() {
clearResults('clearTimeout-results');
logResult('clearTimeout-results', '开始测试 clearTimeout...', 'info');
try {
const memoryManager = new ArgonMemoryManager();
let executed = false;
const id = memoryManager.setTimeout(() => {
executed = true;
}, 100);
if (memoryManager.timers.has(id)) {
logResult('clearTimeout-results', '✓ setTimeout ID 已被跟踪', 'pass');
} else {
logResult('clearTimeout-results', '✗ setTimeout ID 未被跟踪', 'fail');
}
// 立即清除
memoryManager.clearTimeout(id);
if (!memoryManager.timers.has(id)) {
logResult('clearTimeout-results', '✓ clearTimeout 后从跟踪集合中移除', 'pass');
} else {
logResult('clearTimeout-results', '✗ clearTimeout 后未从跟踪集合中移除', 'fail');
}
// 等待一段时间,验证未执行
setTimeout(() => {
if (!executed) {
logResult('clearTimeout-results', '✓ clearTimeout 后回调函数未执行', 'pass');
} else {
logResult('clearTimeout-results', '✗ clearTimeout 后回调函数仍然执行了', 'fail');
}
// 测试 cancelAnimationFrame
let frameExecuted = false;
const frameId = memoryManager.requestAnimationFrame(() => {
frameExecuted = true;
});
memoryManager.cancelAnimationFrame(frameId);
if (!memoryManager.frames.has(frameId)) {
logResult('clearTimeout-results', '✓ cancelAnimationFrame 后从跟踪集合中移除', 'pass');
} else {
logResult('clearTimeout-results', '✗ cancelAnimationFrame 后未从跟踪集合中移除', 'fail');
}
setTimeout(() => {
if (!frameExecuted) {
logResult('clearTimeout-results', '✓ cancelAnimationFrame 后回调函数未执行', 'pass');
} else {
logResult('clearTimeout-results', '✗ cancelAnimationFrame 后回调函数仍然执行了', 'fail');
}
logResult('clearTimeout-results', '✅ clearTimeout 测试完成', 'info');
}, 50);
}, 150);
} catch (error) {
logResult('clearTimeout-results', `✗ 测试出错: ${error.message}`, 'fail');
}
}
// 测试 5: clearAll 统一清理
function testClearAll() {
clearResults('clearAll-results');
logResult('clearAll-results', '开始测试 clearAll 统一清理...', 'info');
try {
const memoryManager = new ArgonMemoryManager();
let timeoutCount = 0;
let intervalCount = 0;
let frameCount = 0;
// 创建多个定时器
memoryManager.setTimeout(() => { timeoutCount++; }, 200);
memoryManager.setTimeout(() => { timeoutCount++; }, 300);
memoryManager.setInterval(() => { intervalCount++; }, 50);
memoryManager.setInterval(() => { intervalCount++; }, 60);
memoryManager.requestAnimationFrame(() => { frameCount++; });
memoryManager.requestAnimationFrame(() => { frameCount++; });
const stats = memoryManager.getStats();
logResult('clearAll-results', `创建定时器 - timers: ${stats.timers}, intervals: ${stats.intervals}, frames: ${stats.frames}`, 'info');
if (stats.timers === 2 && stats.intervals === 2 && stats.frames === 2) {
logResult('clearAll-results', '✓ 所有定时器已创建并跟踪', 'pass');
} else {
logResult('clearAll-results', '✗ 定时器创建或跟踪失败', 'fail');
}
// 清理所有
memoryManager.clearAll();
const statsAfter = memoryManager.getStats();
logResult('clearAll-results', `清理后 - timers: ${statsAfter.timers}, intervals: ${statsAfter.intervals}, frames: ${statsAfter.frames}`, 'info');
if (statsAfter.timers === 0 && statsAfter.intervals === 0 && statsAfter.frames === 0) {
logResult('clearAll-results', '✓ clearAll 后所有跟踪集合已清空', 'pass');
} else {
logResult('clearAll-results', '✗ clearAll 后跟踪集合未完全清空', 'fail');
}
// 等待一段时间,验证所有回调都未执行
setTimeout(() => {
if (timeoutCount === 0 && intervalCount === 0 && frameCount === 0) {
logResult('clearAll-results', '✓ clearAll 后所有回调函数都未执行', 'pass');
} else {
logResult('clearAll-results', `✗ clearAll 后仍有回调执行 (timeout: ${timeoutCount}, interval: ${intervalCount}, frame: ${frameCount})`, 'fail');
}
logResult('clearAll-results', '✅ clearAll 统一清理测试完成', 'info');
}, 400);
} catch (error) {
logResult('clearAll-results', `✗ 测试出错: ${error.message}`, 'fail');
}
}
// 测试 6: 参数传递
function testArgumentPassing() {
clearResults('argumentPassing-results');
logResult('argumentPassing-results', '开始测试参数传递...', 'info');
try {
const memoryManager = new ArgonMemoryManager();
// 测试 setTimeout 参数传递
let timeoutArgs = null;
memoryManager.setTimeout((a, b, c) => {
timeoutArgs = [a, b, c];
}, 50, 'arg1', 'arg2', 'arg3');
// 测试 setInterval 参数传递
let intervalArgs = null;
const intervalId = memoryManager.setInterval((x, y) => {
if (!intervalArgs) {
intervalArgs = [x, y];
}
}, 50, 'test1', 'test2');
setTimeout(() => {
// 验证 setTimeout 参数
if (timeoutArgs && timeoutArgs[0] === 'arg1' && timeoutArgs[1] === 'arg2' && timeoutArgs[2] === 'arg3') {
logResult('argumentPassing-results', '✓ setTimeout 参数传递正确', 'pass');
} else {
logResult('argumentPassing-results', `✗ setTimeout 参数传递错误: ${JSON.stringify(timeoutArgs)}`, 'fail');
}
// 验证 setInterval 参数
if (intervalArgs && intervalArgs[0] === 'test1' && intervalArgs[1] === 'test2') {
logResult('argumentPassing-results', '✓ setInterval 参数传递正确', 'pass');
} else {
logResult('argumentPassing-results', `✗ setInterval 参数传递错误: ${JSON.stringify(intervalArgs)}`, 'fail');
}
memoryManager.clearInterval(intervalId);
logResult('argumentPassing-results', '✅ 参数传递测试完成', 'info');
}, 150);
} catch (error) {
logResult('argumentPassing-results', `✗ 测试出错: ${error.message}`, 'fail');
}
}
// 测试 7: getStats 统计信息
function testGetStats() {
clearResults('getStats-results');
logResult('getStats-results', '开始测试 getStats 统计信息...', 'info');
try {
const memoryManager = new ArgonMemoryManager();
// 初始状态
let stats = memoryManager.getStats();
if (stats.timers === 0 && stats.intervals === 0 && stats.frames === 0 && stats.total === 0) {
logResult('getStats-results', '✓ 初始状态统计信息正确(全为 0', 'pass');
} else {
logResult('getStats-results', `✗ 初始状态统计信息错误: ${JSON.stringify(stats)}`, 'fail');
}
// 创建各种定时器
memoryManager.setTimeout(() => {}, 1000);
memoryManager.setTimeout(() => {}, 2000);
memoryManager.setInterval(() => {}, 1000);
memoryManager.requestAnimationFrame(() => {});
memoryManager.requestAnimationFrame(() => {});
memoryManager.requestAnimationFrame(() => {});
stats = memoryManager.getStats();
logResult('getStats-results', `当前统计: ${JSON.stringify(stats)}`, 'info');
if (stats.timers === 2 && stats.intervals === 1 && stats.frames === 3 && stats.total === 6) {
logResult('getStats-results', '✓ 创建定时器后统计信息正确', 'pass');
} else {
logResult('getStats-results', `✗ 统计信息错误: ${JSON.stringify(stats)}`, 'fail');
}
// 清理所有
memoryManager.clearAll();
stats = memoryManager.getStats();
if (stats.timers === 0 && stats.intervals === 0 && stats.frames === 0 && stats.total === 0) {
logResult('getStats-results', '✓ clearAll 后统计信息正确(全为 0', 'pass');
} else {
logResult('getStats-results', `✗ clearAll 后统计信息错误: ${JSON.stringify(stats)}`, 'fail');
}
logResult('getStats-results', '✅ getStats 统计信息测试完成', 'info');
} catch (error) {
logResult('getStats-results', `✗ 测试出错: ${error.message}`, 'fail');
}
}
// 运行所有测试
function runAllTests() {
clearResults('all-tests-results');
logResult('all-tests-results', '🚀 开始运行所有测试...', 'info');
testSetTimeout();
setTimeout(() => testSetInterval(), 200);
setTimeout(() => testRequestAnimationFrame(), 400);
setTimeout(() => testClearTimeout(), 600);
setTimeout(() => testClearAll(), 1000);
setTimeout(() => testArgumentPassing(), 1500);
setTimeout(() => testGetStats(), 1700);
setTimeout(() => {
logResult('all-tests-results', '✅ 所有测试已启动,请查看各模块的测试结果', 'info');
}, 1800);
}
// 页面加载完成后的提示
window.addEventListener('load', () => {
console.log('ArgonMemoryManager 测试页面已加载');
console.log('ArgonMemoryManager:', ArgonMemoryManager);
});
</script>
</body>
</html>

View File

@@ -0,0 +1,216 @@
/**
* ArgonMemoryManager 单元测试
* 测试内存管理模块的定时器和动画帧跟踪功能
*/
// 模拟浏览器环境
if (typeof window === 'undefined') {
global.window = global;
global.setTimeout = setTimeout;
global.clearTimeout = clearTimeout;
global.setInterval = setInterval;
global.clearInterval = clearInterval;
global.requestAnimationFrame = (callback) => setTimeout(callback, 16);
global.cancelAnimationFrame = clearTimeout;
}
// 加载模块
require('./argon-performance.js');
const ArgonMemoryManager = window.ArgonMemoryManager;
describe('ArgonMemoryManager', () => {
let memoryManager;
beforeEach(() => {
memoryManager = new ArgonMemoryManager();
});
afterEach(() => {
// 清理所有定时器
memoryManager.clearAll();
});
// Feature: resource-cpu-optimization, Example: setTimeout 跟踪
test('should track setTimeout and auto-remove after execution', (done) => {
let executed = false;
const id = memoryManager.setTimeout(() => {
executed = true;
}, 10);
// 验证 ID 被跟踪
expect(memoryManager.timers.has(id)).toBe(true);
expect(memoryManager.getStats().timers).toBe(1);
// 等待执行完成
setTimeout(() => {
expect(executed).toBe(true);
// 验证执行后自动移除
expect(memoryManager.timers.has(id)).toBe(false);
expect(memoryManager.getStats().timers).toBe(0);
done();
}, 50);
});
// Feature: resource-cpu-optimization, Example: setInterval 跟踪
test('should track setInterval', (done) => {
let count = 0;
const id = memoryManager.setInterval(() => {
count++;
}, 10);
// 验证 ID 被跟踪
expect(memoryManager.intervals.has(id)).toBe(true);
expect(memoryManager.getStats().intervals).toBe(1);
// 等待执行几次
setTimeout(() => {
expect(count).toBeGreaterThan(0);
// 手动清除
memoryManager.clearInterval(id);
expect(memoryManager.intervals.has(id)).toBe(false);
expect(memoryManager.getStats().intervals).toBe(0);
done();
}, 50);
});
// Feature: resource-cpu-optimization, Example: requestAnimationFrame 跟踪
test('should track requestAnimationFrame and auto-remove after execution', (done) => {
let executed = false;
const id = memoryManager.requestAnimationFrame(() => {
executed = true;
});
// 验证 ID 被跟踪
expect(memoryManager.frames.has(id)).toBe(true);
expect(memoryManager.getStats().frames).toBe(1);
// 等待执行完成
setTimeout(() => {
expect(executed).toBe(true);
// 验证执行后自动移除
expect(memoryManager.frames.has(id)).toBe(false);
expect(memoryManager.getStats().frames).toBe(0);
done();
}, 50);
});
// Feature: resource-cpu-optimization, Example: clearTimeout 移除跟踪
test('should remove timer from tracking when cleared', () => {
const id = memoryManager.setTimeout(() => {}, 1000);
expect(memoryManager.timers.has(id)).toBe(true);
memoryManager.clearTimeout(id);
expect(memoryManager.timers.has(id)).toBe(false);
});
// Feature: resource-cpu-optimization, Example: cancelAnimationFrame 移除跟踪
test('should remove frame from tracking when cancelled', () => {
const id = memoryManager.requestAnimationFrame(() => {});
expect(memoryManager.frames.has(id)).toBe(true);
memoryManager.cancelAnimationFrame(id);
expect(memoryManager.frames.has(id)).toBe(false);
});
// Feature: resource-cpu-optimization, Example: clearAll 清理所有定时器
test('should clear all timers, intervals and frames', (done) => {
// 创建多个定时器
memoryManager.setTimeout(() => {}, 1000);
memoryManager.setTimeout(() => {}, 2000);
memoryManager.setInterval(() => {}, 100);
memoryManager.setInterval(() => {}, 200);
memoryManager.requestAnimationFrame(() => {});
memoryManager.requestAnimationFrame(() => {});
const stats = memoryManager.getStats();
expect(stats.timers).toBe(2);
expect(stats.intervals).toBe(2);
expect(stats.frames).toBe(2);
expect(stats.total).toBe(6);
// 清理所有
memoryManager.clearAll();
const statsAfter = memoryManager.getStats();
expect(statsAfter.timers).toBe(0);
expect(statsAfter.intervals).toBe(0);
expect(statsAfter.frames).toBe(0);
expect(statsAfter.total).toBe(0);
done();
});
// Feature: resource-cpu-optimization, Example: 多个定时器跟踪
test('should track multiple timers independently', () => {
const id1 = memoryManager.setTimeout(() => {}, 1000);
const id2 = memoryManager.setTimeout(() => {}, 2000);
const id3 = memoryManager.setTimeout(() => {}, 3000);
expect(memoryManager.getStats().timers).toBe(3);
memoryManager.clearTimeout(id2);
expect(memoryManager.getStats().timers).toBe(2);
expect(memoryManager.timers.has(id1)).toBe(true);
expect(memoryManager.timers.has(id2)).toBe(false);
expect(memoryManager.timers.has(id3)).toBe(true);
});
// Feature: resource-cpu-optimization, Example: 传递参数给回调函数
test('should pass arguments to setTimeout callback', (done) => {
let receivedArgs = null;
memoryManager.setTimeout((a, b, c) => {
receivedArgs = [a, b, c];
}, 10, 'arg1', 'arg2', 'arg3');
setTimeout(() => {
expect(receivedArgs).toEqual(['arg1', 'arg2', 'arg3']);
done();
}, 50);
});
// Feature: resource-cpu-optimization, Example: 传递参数给 setInterval 回调函数
test('should pass arguments to setInterval callback', (done) => {
let receivedArgs = null;
const id = memoryManager.setInterval((a, b) => {
receivedArgs = [a, b];
}, 10, 'test1', 'test2');
setTimeout(() => {
expect(receivedArgs).toEqual(['test1', 'test2']);
memoryManager.clearInterval(id);
done();
}, 50);
});
// Feature: resource-cpu-optimization, Example: getStats 返回正确的统计信息
test('should return correct stats', () => {
expect(memoryManager.getStats()).toEqual({
timers: 0,
intervals: 0,
frames: 0,
total: 0
});
memoryManager.setTimeout(() => {}, 1000);
memoryManager.setInterval(() => {}, 1000);
memoryManager.requestAnimationFrame(() => {});
expect(memoryManager.getStats()).toEqual({
timers: 1,
intervals: 1,
frames: 1,
total: 3
});
});
});

View File

@@ -677,6 +677,176 @@ class ArgonRenderOptimizer {
} }
} }
// ==========================================================================
// 内存管理模块
// ==========================================================================
/**
* 内存管理类
* 跟踪和管理定时器、间隔定时器和动画帧,确保正确清理避免内存泄漏
*
* @class ArgonMemoryManager
*/
class ArgonMemoryManager {
/**
* 构造函数
* 初始化 ID 跟踪集合
*/
constructor() {
this.timers = new Set(); // setTimeout ID 集合
this.intervals = new Set(); // setInterval ID 集合
this.frames = new Set(); // requestAnimationFrame ID 集合
}
/**
* 设置定时器并跟踪
* 包装原生 setTimeout自动跟踪 timer ID
*
* @param {Function} callback - 回调函数
* @param {number} delay - 延迟时间(毫秒)
* @param {...*} args - 传递给回调函数的参数
* @returns {number} timer ID可用于手动清除
*/
setTimeout(callback, delay, ...args) {
const id = setTimeout(() => {
// 执行完成后自动从跟踪集合中移除
this.timers.delete(id);
callback(...args);
}, delay);
this.timers.add(id);
return id;
}
/**
* 设置间隔定时器并跟踪
* 包装原生 setInterval自动跟踪 interval ID
*
* @param {Function} callback - 回调函数
* @param {number} interval - 间隔时间(毫秒)
* @param {...*} args - 传递给回调函数的参数
* @returns {number} interval ID可用于手动清除
*/
setInterval(callback, interval, ...args) {
const id = setInterval(() => {
callback(...args);
}, interval);
this.intervals.add(id);
return id;
}
/**
* 请求动画帧并跟踪
* 包装原生 requestAnimationFrame自动跟踪 frame ID
*
* @param {Function} callback - 回调函数
* @returns {number} frame ID可用于手动取消
*/
requestAnimationFrame(callback) {
const id = requestAnimationFrame((timestamp) => {
// 执行完成后自动从跟踪集合中移除
this.frames.delete(id);
callback(timestamp);
});
this.frames.add(id);
return id;
}
/**
* 清除定时器
* 包装原生 clearTimeout同时从跟踪集合中移除
*
* @param {number} id - timer ID
* @returns {void}
*/
clearTimeout(id) {
clearTimeout(id);
this.timers.delete(id);
}
/**
* 清除间隔定时器
* 包装原生 clearInterval同时从跟踪集合中移除
*
* @param {number} id - interval ID
* @returns {void}
*/
clearInterval(id) {
clearInterval(id);
this.intervals.delete(id);
}
/**
* 取消动画帧
* 包装原生 cancelAnimationFrame同时从跟踪集合中移除
*
* @param {number} id - frame ID
* @returns {void}
*/
cancelAnimationFrame(id) {
cancelAnimationFrame(id);
this.frames.delete(id);
}
/**
* 清理所有定时器和动画帧
* 通常在 PJAX 页面切换或组件销毁时调用
* 确保所有待执行的回调都被取消,避免内存泄漏
*
* @returns {void}
*/
clearAll() {
// 清除所有 setTimeout
this.timers.forEach(id => {
try {
clearTimeout(id);
} catch (e) {
// 静默失败ID 可能已失效
}
});
// 清除所有 setInterval
this.intervals.forEach(id => {
try {
clearInterval(id);
} catch (e) {
// 静默失败ID 可能已失效
}
});
// 取消所有 requestAnimationFrame
this.frames.forEach(id => {
try {
cancelAnimationFrame(id);
} catch (e) {
// 静默失败ID 可能已失效
}
});
// 清空所有集合
this.timers.clear();
this.intervals.clear();
this.frames.clear();
}
/**
* 获取当前跟踪的定时器数量
* 用于调试和性能监控
*
* @returns {Object} 包含各类定时器数量的对象
*/
getStats() {
return {
timers: this.timers.size,
intervals: this.intervals.size,
frames: this.frames.size,
total: this.timers.size + this.intervals.size + this.frames.size
};
}
}
// ========================================================================== // ==========================================================================
// 模块导出和初始化接口 // 模块导出和初始化接口
// ========================================================================== // ==========================================================================
@@ -702,5 +872,6 @@ if (typeof window !== 'undefined') {
window.ArgonEventManager = ArgonEventManager; window.ArgonEventManager = ArgonEventManager;
window.ArgonResourceLoader = ArgonResourceLoader; window.ArgonResourceLoader = ArgonResourceLoader;
window.ArgonRenderOptimizer = ArgonRenderOptimizer; window.ArgonRenderOptimizer = ArgonRenderOptimizer;
window.ArgonMemoryManager = ArgonMemoryManager;
window.initArgonPerformance = initArgonPerformance; window.initArgonPerformance = initArgonPerformance;
} }