feat: 实现 GPU 加速管理功能
- 实现 enableGPU() 方法设置 will-change 属性 - 实现 disableGPU() 方法移除 will-change 属性 - 实现动画数量限制逻辑(最多 3 个同时运行) - 实现动画队列自动管理 - 添加 startAnimation() 和 endAnimation() 方法 - 添加 getActiveAnimationCount() 和 getQueuedAnimationCount() 查询方法 - 添加 clearAllAnimations() 清理方法 - 添加错误处理机制 - 创建交互式测试页面和自动化测试 - 创建详细的使用文档 验证需求: - 需求 5.2: 动画时使用 will-change 提示浏览器创建合成层 - 需求 5.3: 动画完成时移除 will-change 属性释放资源 - 需求 5.5: 限制同时运行的动画数量不超过 3 个
This commit is contained in:
294
test-gpu-acceleration.test.js
Normal file
294
test-gpu-acceleration.test.js
Normal file
@@ -0,0 +1,294 @@
|
||||
/**
|
||||
* GPU 加速管理功能测试
|
||||
* 测试 ArgonRenderOptimizer 的 GPU 加速和动画限制功能
|
||||
*/
|
||||
|
||||
// 模拟浏览器环境
|
||||
global.window = global;
|
||||
global.document = {
|
||||
createElement: () => ({
|
||||
style: {},
|
||||
addEventListener: () => {},
|
||||
appendChild: () => {}
|
||||
}),
|
||||
querySelector: () => null,
|
||||
getElementById: () => null,
|
||||
head: {
|
||||
appendChild: () => {}
|
||||
}
|
||||
};
|
||||
|
||||
global.requestAnimationFrame = (callback) => {
|
||||
return setTimeout(callback, 16);
|
||||
};
|
||||
|
||||
global.cancelAnimationFrame = (id) => {
|
||||
clearTimeout(id);
|
||||
};
|
||||
|
||||
// 加载性能优化模块
|
||||
require('./argon-performance.js');
|
||||
|
||||
const { ArgonRenderOptimizer } = global;
|
||||
|
||||
// 测试套件
|
||||
console.log('='.repeat(60));
|
||||
console.log('GPU 加速管理功能测试');
|
||||
console.log('='.repeat(60));
|
||||
|
||||
// 测试 1: enableGPU() 方法
|
||||
console.log('\n测试 1: enableGPU() 方法');
|
||||
console.log('-'.repeat(60));
|
||||
|
||||
const renderOptimizer = new ArgonRenderOptimizer();
|
||||
const testElement1 = { style: {} };
|
||||
|
||||
renderOptimizer.enableGPU(testElement1);
|
||||
|
||||
if (testElement1.style.willChange === 'transform, opacity') {
|
||||
console.log('✓ enableGPU() 正确设置 will-change 属性');
|
||||
} else {
|
||||
console.error('✗ enableGPU() 未正确设置 will-change 属性');
|
||||
console.error(` 期望: "transform, opacity"`);
|
||||
console.error(` 实际: "${testElement1.style.willChange}"`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 测试 null 元素
|
||||
renderOptimizer.enableGPU(null);
|
||||
console.log('✓ enableGPU() 正确处理 null 元素');
|
||||
|
||||
// 测试 2: disableGPU() 方法
|
||||
console.log('\n测试 2: disableGPU() 方法');
|
||||
console.log('-'.repeat(60));
|
||||
|
||||
const testElement2 = { style: { willChange: 'transform, opacity' } };
|
||||
|
||||
renderOptimizer.disableGPU(testElement2);
|
||||
|
||||
if (testElement2.style.willChange === 'auto') {
|
||||
console.log('✓ disableGPU() 正确移除 will-change 属性');
|
||||
} else {
|
||||
console.error('✗ disableGPU() 未正确移除 will-change 属性');
|
||||
console.error(` 期望: "auto"`);
|
||||
console.error(` 实际: "${testElement2.style.willChange}"`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 测试 null 元素
|
||||
renderOptimizer.disableGPU(null);
|
||||
console.log('✓ disableGPU() 正确处理 null 元素');
|
||||
|
||||
// 测试 3: 动画数量限制
|
||||
console.log('\n测试 3: 动画数量限制(最多 3 个)');
|
||||
console.log('-'.repeat(60));
|
||||
|
||||
const renderOptimizer2 = new ArgonRenderOptimizer();
|
||||
const elements = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
elements.push({ style: {}, id: `element-${i}` });
|
||||
}
|
||||
|
||||
// 启动 5 个动画
|
||||
const results = [];
|
||||
elements.forEach((element, index) => {
|
||||
const started = renderOptimizer2.startAnimation(element, (el) => {
|
||||
// 模拟动画
|
||||
});
|
||||
results.push(started);
|
||||
});
|
||||
|
||||
// 验证前 3 个立即启动,后 2 个进入队列
|
||||
const immediateStarts = results.filter(r => r === true).length;
|
||||
const queued = results.filter(r => r === false).length;
|
||||
|
||||
if (immediateStarts === 3) {
|
||||
console.log(`✓ 前 3 个动画立即启动`);
|
||||
} else {
|
||||
console.error(`✗ 立即启动的动画数量错误`);
|
||||
console.error(` 期望: 3`);
|
||||
console.error(` 实际: ${immediateStarts}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (queued === 2) {
|
||||
console.log(`✓ 后 2 个动画进入等待队列`);
|
||||
} else {
|
||||
console.error(`✗ 等待队列的动画数量错误`);
|
||||
console.error(` 期望: 2`);
|
||||
console.error(` 实际: ${queued}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 验证活动动画数量
|
||||
const activeCount = renderOptimizer2.getActiveAnimationCount();
|
||||
if (activeCount === 3) {
|
||||
console.log(`✓ 活动动画数量: ${activeCount}`);
|
||||
} else {
|
||||
console.error(`✗ 活动动画数量错误`);
|
||||
console.error(` 期望: 3`);
|
||||
console.error(` 实际: ${activeCount}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 验证等待队列数量
|
||||
const queuedCount = renderOptimizer2.getQueuedAnimationCount();
|
||||
if (queuedCount === 2) {
|
||||
console.log(`✓ 等待队列数量: ${queuedCount}`);
|
||||
} else {
|
||||
console.error(`✗ 等待队列数量错误`);
|
||||
console.error(` 期望: 2`);
|
||||
console.error(` 实际: ${queuedCount}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 测试 4: 动画完成后自动启动队列中的下一个
|
||||
console.log('\n测试 4: 动画队列自动管理');
|
||||
console.log('-'.repeat(60));
|
||||
|
||||
// 结束第一个动画
|
||||
renderOptimizer2.endAnimation(elements[0]);
|
||||
|
||||
// 验证活动动画数量仍为 3(队列中的一个自动启动)
|
||||
const activeAfterEnd = renderOptimizer2.getActiveAnimationCount();
|
||||
if (activeAfterEnd === 3) {
|
||||
console.log(`✓ 动画结束后,队列中的动画自动启动`);
|
||||
console.log(` 活动动画数量保持: ${activeAfterEnd}`);
|
||||
} else {
|
||||
console.error(`✗ 动画队列自动管理失败`);
|
||||
console.error(` 期望活动动画数量: 3`);
|
||||
console.error(` 实际活动动画数量: ${activeAfterEnd}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 验证等待队列减少
|
||||
const queuedAfterEnd = renderOptimizer2.getQueuedAnimationCount();
|
||||
if (queuedAfterEnd === 1) {
|
||||
console.log(`✓ 等待队列数量减少: ${queuedAfterEnd}`);
|
||||
} else {
|
||||
console.error(`✗ 等待队列数量错误`);
|
||||
console.error(` 期望: 1`);
|
||||
console.error(` 实际: ${queuedAfterEnd}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 测试 5: GPU 加速生命周期
|
||||
console.log('\n测试 5: GPU 加速生命周期');
|
||||
console.log('-'.repeat(60));
|
||||
|
||||
const renderOptimizer3 = new ArgonRenderOptimizer();
|
||||
const animElement = { style: {} };
|
||||
|
||||
// 启动动画应该启用 GPU 加速
|
||||
renderOptimizer3.startAnimation(animElement, (el) => {
|
||||
// 动画函数
|
||||
});
|
||||
|
||||
if (animElement.style.willChange === 'transform, opacity') {
|
||||
console.log('✓ 动画启动时自动启用 GPU 加速');
|
||||
} else {
|
||||
console.error('✗ 动画启动时未启用 GPU 加速');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 结束动画应该禁用 GPU 加速
|
||||
renderOptimizer3.endAnimation(animElement);
|
||||
|
||||
if (animElement.style.willChange === 'auto') {
|
||||
console.log('✓ 动画结束时自动禁用 GPU 加速');
|
||||
} else {
|
||||
console.error('✗ 动画结束时未禁用 GPU 加速');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 测试 6: clearAllAnimations()
|
||||
console.log('\n测试 6: clearAllAnimations() 方法');
|
||||
console.log('-'.repeat(60));
|
||||
|
||||
const renderOptimizer4 = new ArgonRenderOptimizer();
|
||||
const clearElements = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const el = { style: {} };
|
||||
clearElements.push(el);
|
||||
renderOptimizer4.startAnimation(el, () => {});
|
||||
}
|
||||
|
||||
// 清除所有动画
|
||||
renderOptimizer4.clearAllAnimations();
|
||||
|
||||
// 验证所有动画都被清除
|
||||
const activeAfterClear = renderOptimizer4.getActiveAnimationCount();
|
||||
const queuedAfterClear = renderOptimizer4.getQueuedAnimationCount();
|
||||
|
||||
if (activeAfterClear === 0) {
|
||||
console.log('✓ 所有活动动画已清除');
|
||||
} else {
|
||||
console.error(`✗ 活动动画未完全清除,剩余: ${activeAfterClear}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (queuedAfterClear === 0) {
|
||||
console.log('✓ 等待队列已清空');
|
||||
} else {
|
||||
console.error(`✗ 等待队列未完全清空,剩余: ${queuedAfterClear}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 验证所有元素的 GPU 加速都被禁用
|
||||
const allDisabled = clearElements.every(el => el.style.willChange === 'auto');
|
||||
if (allDisabled) {
|
||||
console.log('✓ 所有元素的 GPU 加速已禁用');
|
||||
} else {
|
||||
console.error('✗ 部分元素的 GPU 加速未禁用');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 测试 7: 错误处理
|
||||
console.log('\n测试 7: 错误处理');
|
||||
console.log('-'.repeat(60));
|
||||
|
||||
const renderOptimizer5 = new ArgonRenderOptimizer();
|
||||
const errorElement = { style: {} };
|
||||
|
||||
// 测试动画函数抛出错误
|
||||
let errorCaught = false;
|
||||
renderOptimizer5.startAnimation(errorElement, (el) => {
|
||||
throw new Error('Test error');
|
||||
});
|
||||
|
||||
// 验证错误不会导致程序崩溃,且动画被正确清理
|
||||
setTimeout(() => {
|
||||
const activeAfterError = renderOptimizer5.getActiveAnimationCount();
|
||||
if (activeAfterError === 0) {
|
||||
console.log('✓ 动画函数错误被正确处理,动画已清理');
|
||||
} else {
|
||||
console.error('✗ 动画函数错误处理失败');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (errorElement.style.willChange === 'auto') {
|
||||
console.log('✓ 错误后 GPU 加速已禁用');
|
||||
} else {
|
||||
console.error('✗ 错误后 GPU 加速未禁用');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 所有测试通过
|
||||
console.log('\n' + '='.repeat(60));
|
||||
console.log('✓ 所有测试通过!');
|
||||
console.log('='.repeat(60));
|
||||
console.log('\n测试摘要:');
|
||||
console.log(' ✓ enableGPU() 方法正常工作');
|
||||
console.log(' ✓ disableGPU() 方法正常工作');
|
||||
console.log(' ✓ 动画数量限制为 3 个');
|
||||
console.log(' ✓ 动画队列自动管理');
|
||||
console.log(' ✓ GPU 加速生命周期管理');
|
||||
console.log(' ✓ clearAllAnimations() 方法正常工作');
|
||||
console.log(' ✓ 错误处理机制正常');
|
||||
console.log('\n需求验证:');
|
||||
console.log(' ✓ 需求 5.2: 动画时使用 will-change 提示浏览器创建合成层');
|
||||
console.log(' ✓ 需求 5.3: 动画完成时移除 will-change 属性释放资源');
|
||||
console.log(' ✓ 需求 5.5: 限制同时运行的动画数量不超过 3 个');
|
||||
|
||||
process.exit(0);
|
||||
}, 100);
|
||||
Reference in New Issue
Block a user