- 实现构造函数,初始化读写队列和调度状态 - 实现 read() 方法:将 DOM 读取操作加入队列 - 实现 write() 方法:将 DOM 写入操作加入队列 - 实现 _schedule() 私有方法:使用 requestAnimationFrame 调度执行 - 实现 _flush() 私有方法:批量执行队列操作(先读后写) - 实现 enableGPU() 方法:设置 will-change 属性启用 GPU 加速 - 实现 disableGPU() 方法:移除 will-change 属性释放资源 - 添加错误处理机制,确保单个操作失败不影响其他操作 - 在测试文件中添加完整的渲染优化模块测试 - 创建使用指南文档 RENDER_OPTIMIZER_USAGE.md - 导出 ArgonRenderOptimizer 类供其他模块使用 验证需求:2.3, 2.4, 17.1, 17.2
588 lines
18 KiB
HTML
588 lines
18 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Argon 性能优化模块 - 基础测试</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;
|
||
}
|
||
#test-elements {
|
||
display: none;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<h1>🚀 Argon 性能优化模块 - 基础测试</h1>
|
||
|
||
<!-- 测试用的 DOM 元素 -->
|
||
<div id="test-elements">
|
||
<div class="navbar">Navbar</div>
|
||
<div id="content">Content</div>
|
||
<div id="leftbar">Leftbar</div>
|
||
<div id="sidebar">Sidebar</div>
|
||
<div id="fabtn_back_to_top">Back to Top</div>
|
||
<div id="fabtn_reading_progress">Reading Progress</div>
|
||
<div id="comments">Comments</div>
|
||
<div id="post_comment">Post Comment</div>
|
||
</div>
|
||
|
||
<!-- DOM 缓存测试 -->
|
||
<div class="test-section">
|
||
<h2>1. DOM 缓存模块测试</h2>
|
||
<button onclick="testDOMCache()">运行测试</button>
|
||
<div id="dom-cache-results"></div>
|
||
</div>
|
||
|
||
<!-- 事件管理测试 -->
|
||
<div class="test-section">
|
||
<h2>2. 事件管理模块测试</h2>
|
||
<button onclick="testEventManager()">运行测试</button>
|
||
<div id="event-manager-results"></div>
|
||
</div>
|
||
|
||
<!-- 节流测试 -->
|
||
<div class="test-section">
|
||
<h2>3. 节流(Throttle)功能测试</h2>
|
||
<button onclick="testThrottle()">运行测试</button>
|
||
<div id="throttle-results"></div>
|
||
</div>
|
||
|
||
<!-- 防抖测试 -->
|
||
<div class="test-section">
|
||
<h2>4. 防抖(Debounce)功能测试</h2>
|
||
<button onclick="testDebounce()">运行测试</button>
|
||
<div id="debounce-results"></div>
|
||
</div>
|
||
|
||
<!-- 资源加载测试 -->
|
||
<div class="test-section">
|
||
<h2>5. 资源加载模块测试</h2>
|
||
<button onclick="testResourceLoader()">运行测试</button>
|
||
<div id="resource-loader-results"></div>
|
||
<!-- 测试用的元素 -->
|
||
<div style="display: none;">
|
||
<pre><code>console.log('test');</code></pre>
|
||
<div class="post-content"><img src="test.jpg" alt="test"></div>
|
||
<div data-tippy-content="Test tooltip">Hover me</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 渲染优化测试 -->
|
||
<div class="test-section">
|
||
<h2>6. 渲染优化模块测试</h2>
|
||
<button onclick="testRenderOptimizer()">运行测试</button>
|
||
<div id="render-optimizer-results"></div>
|
||
<div id="test-animation-element" style="width: 100px; height: 100px; background: #4CAF50; margin: 10px 0;"></div>
|
||
</div>
|
||
|
||
<!-- 综合测试 -->
|
||
<div class="test-section">
|
||
<h2>7. 综合测试</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: DOM 缓存模块
|
||
function testDOMCache() {
|
||
clearResults('dom-cache-results');
|
||
logResult('dom-cache-results', '开始测试 DOM 缓存模块...', 'info');
|
||
|
||
try {
|
||
// 创建实例
|
||
const cache = new ArgonDOMCache();
|
||
logResult('dom-cache-results', '✓ ArgonDOMCache 实例创建成功', 'pass');
|
||
|
||
// 测试初始化
|
||
cache.init();
|
||
if (cache.initialized) {
|
||
logResult('dom-cache-results', '✓ 缓存初始化成功', 'pass');
|
||
} else {
|
||
logResult('dom-cache-results', '✗ 缓存初始化失败', 'fail');
|
||
}
|
||
|
||
// 测试获取存在的元素
|
||
const toolbar = cache.get('toolbar');
|
||
if (toolbar && toolbar.classList.contains('navbar')) {
|
||
logResult('dom-cache-results', '✓ 成功获取缓存的 toolbar 元素', 'pass');
|
||
} else {
|
||
logResult('dom-cache-results', '✗ 获取 toolbar 元素失败', 'fail');
|
||
}
|
||
|
||
// 测试获取不存在的元素
|
||
const nonExistent = cache.get('non-existent');
|
||
if (nonExistent === null) {
|
||
logResult('dom-cache-results', '✓ 不存在的元素正确返回 null', 'pass');
|
||
} else {
|
||
logResult('dom-cache-results', '✗ 不存在的元素应返回 null', 'fail');
|
||
}
|
||
|
||
// 测试设置缓存
|
||
const testElement = document.createElement('div');
|
||
cache.set('test-element', testElement);
|
||
if (cache.get('test-element') === testElement) {
|
||
logResult('dom-cache-results', '✓ 设置和获取自定义缓存成功', 'pass');
|
||
} else {
|
||
logResult('dom-cache-results', '✗ 设置自定义缓存失败', 'fail');
|
||
}
|
||
|
||
// 测试清空缓存
|
||
cache.clear();
|
||
if (!cache.initialized && cache.get('toolbar') === null) {
|
||
logResult('dom-cache-results', '✓ 清空缓存成功', 'pass');
|
||
} else {
|
||
logResult('dom-cache-results', '✗ 清空缓存失败', 'fail');
|
||
}
|
||
|
||
logResult('dom-cache-results', '✅ DOM 缓存模块测试完成', 'info');
|
||
} catch (error) {
|
||
logResult('dom-cache-results', `✗ 测试出错: ${error.message}`, 'fail');
|
||
}
|
||
}
|
||
|
||
// 测试 2: 事件管理模块
|
||
function testEventManager() {
|
||
clearResults('event-manager-results');
|
||
logResult('event-manager-results', '开始测试事件管理模块...', 'info');
|
||
|
||
try {
|
||
// 创建实例
|
||
const eventManager = new ArgonEventManager();
|
||
logResult('event-manager-results', '✓ ArgonEventManager 实例创建成功', 'pass');
|
||
|
||
// 测试添加事件监听器
|
||
let clickCount = 0;
|
||
const testElement = document.createElement('button');
|
||
const handler = () => { clickCount++; };
|
||
|
||
eventManager.on(testElement, 'click', handler);
|
||
testElement.click();
|
||
|
||
if (clickCount === 1) {
|
||
logResult('event-manager-results', '✓ 事件监听器添加和触发成功', 'pass');
|
||
} else {
|
||
logResult('event-manager-results', '✗ 事件监听器触发失败', 'fail');
|
||
}
|
||
|
||
// 测试移除事件监听器
|
||
eventManager.off(testElement, 'click');
|
||
testElement.click();
|
||
|
||
if (clickCount === 1) {
|
||
logResult('event-manager-results', '✓ 事件监听器移除成功', 'pass');
|
||
} else {
|
||
logResult('event-manager-results', '✗ 事件监听器移除失败', 'fail');
|
||
}
|
||
|
||
// 测试清空所有监听器
|
||
let count1 = 0, count2 = 0;
|
||
const elem1 = document.createElement('div');
|
||
const elem2 = document.createElement('div');
|
||
|
||
eventManager.on(elem1, 'click', () => { count1++; });
|
||
eventManager.on(elem2, 'click', () => { count2++; });
|
||
|
||
eventManager.clear();
|
||
elem1.click();
|
||
elem2.click();
|
||
|
||
if (count1 === 0 && count2 === 0) {
|
||
logResult('event-manager-results', '✓ 清空所有监听器成功', 'pass');
|
||
} else {
|
||
logResult('event-manager-results', '✗ 清空所有监听器失败', 'fail');
|
||
}
|
||
|
||
logResult('event-manager-results', '✅ 事件管理模块测试完成', 'info');
|
||
} catch (error) {
|
||
logResult('event-manager-results', `✗ 测试出错: ${error.message}`, 'fail');
|
||
}
|
||
}
|
||
|
||
// 测试 3: 节流功能
|
||
function testThrottle() {
|
||
clearResults('throttle-results');
|
||
logResult('throttle-results', '开始测试节流功能...', 'info');
|
||
|
||
try {
|
||
const eventManager = new ArgonEventManager();
|
||
let execCount = 0;
|
||
|
||
const throttledFunc = eventManager.throttle(() => {
|
||
execCount++;
|
||
}, 50);
|
||
|
||
// 快速调用 10 次
|
||
for (let i = 0; i < 10; i++) {
|
||
throttledFunc();
|
||
}
|
||
|
||
logResult('throttle-results', `立即调用 10 次,实际执行: ${execCount} 次`, 'info');
|
||
|
||
// 等待一段时间后检查
|
||
setTimeout(() => {
|
||
logResult('throttle-results', `等待 200ms 后,总执行次数: ${execCount} 次`, 'info');
|
||
|
||
if (execCount >= 1 && execCount <= 5) {
|
||
logResult('throttle-results', '✓ 节流功能正常工作(执行次数在合理范围内)', 'pass');
|
||
} else {
|
||
logResult('throttle-results', `✗ 节流功能异常(执行次数: ${execCount})`, 'fail');
|
||
}
|
||
|
||
logResult('throttle-results', '✅ 节流功能测试完成', 'info');
|
||
}, 200);
|
||
|
||
} catch (error) {
|
||
logResult('throttle-results', `✗ 测试出错: ${error.message}`, 'fail');
|
||
}
|
||
}
|
||
|
||
// 测试 4: 防抖功能
|
||
function testDebounce() {
|
||
clearResults('debounce-results');
|
||
logResult('debounce-results', '开始测试防抖功能...', 'info');
|
||
|
||
try {
|
||
const eventManager = new ArgonEventManager();
|
||
let execCount = 0;
|
||
|
||
const debouncedFunc = eventManager.debounce(() => {
|
||
execCount++;
|
||
logResult('debounce-results', `防抖函数执行,当前执行次数: ${execCount}`, 'info');
|
||
}, 100);
|
||
|
||
// 快速调用 10 次
|
||
for (let i = 0; i < 10; i++) {
|
||
debouncedFunc();
|
||
}
|
||
|
||
logResult('debounce-results', '快速调用 10 次,等待防抖延迟...', 'info');
|
||
|
||
// 等待防抖延迟后检查
|
||
setTimeout(() => {
|
||
if (execCount === 1) {
|
||
logResult('debounce-results', '✓ 防抖功能正常工作(只执行了 1 次)', 'pass');
|
||
} else {
|
||
logResult('debounce-results', `✗ 防抖功能异常(执行了 ${execCount} 次)`, 'fail');
|
||
}
|
||
|
||
// 测试取消功能
|
||
execCount = 0;
|
||
debouncedFunc();
|
||
debouncedFunc.cancel();
|
||
|
||
setTimeout(() => {
|
||
if (execCount === 0) {
|
||
logResult('debounce-results', '✓ 防抖取消功能正常工作', 'pass');
|
||
} else {
|
||
logResult('debounce-results', '✗ 防抖取消功能失败', 'fail');
|
||
}
|
||
|
||
logResult('debounce-results', '✅ 防抖功能测试完成', 'info');
|
||
}, 150);
|
||
}, 150);
|
||
|
||
} catch (error) {
|
||
logResult('debounce-results', `✗ 测试出错: ${error.message}`, 'fail');
|
||
}
|
||
}
|
||
|
||
// 测试 5: 资源加载模块
|
||
function testResourceLoader() {
|
||
clearResults('resource-loader-results');
|
||
logResult('resource-loader-results', '开始测试资源加载模块...', 'info');
|
||
|
||
try {
|
||
// 创建实例
|
||
const loader = new ArgonResourceLoader();
|
||
logResult('resource-loader-results', '✓ ArgonResourceLoader 实例创建成功', 'pass');
|
||
|
||
// 测试 needsLibrary 方法
|
||
const needsPrism = loader.needsLibrary('pre code');
|
||
if (needsPrism) {
|
||
logResult('resource-loader-results', '✓ needsLibrary 检测到页面包含代码块', 'pass');
|
||
} else {
|
||
logResult('resource-loader-results', '✗ needsLibrary 未能检测到代码块', 'fail');
|
||
}
|
||
|
||
const needsZoomify = loader.needsLibrary('.post-content img');
|
||
if (needsZoomify) {
|
||
logResult('resource-loader-results', '✓ needsLibrary 检测到页面包含图片', 'pass');
|
||
} else {
|
||
logResult('resource-loader-results', '✗ needsLibrary 未能检测到图片', 'fail');
|
||
}
|
||
|
||
const needsTippy = loader.needsLibrary('[data-tippy-content]');
|
||
if (needsTippy) {
|
||
logResult('resource-loader-results', '✓ needsLibrary 检测到页面包含提示框元素', 'pass');
|
||
} else {
|
||
logResult('resource-loader-results', '✗ needsLibrary 未能检测到提示框元素', 'fail');
|
||
}
|
||
|
||
// 测试不存在的元素
|
||
const needsNonExistent = loader.needsLibrary('.non-existent-element');
|
||
if (!needsNonExistent) {
|
||
logResult('resource-loader-results', '✓ needsLibrary 正确返回 false(不存在的元素)', 'pass');
|
||
} else {
|
||
logResult('resource-loader-results', '✗ needsLibrary 应返回 false', 'fail');
|
||
}
|
||
|
||
// 测试 loadScript 方法(使用测试 URL)
|
||
logResult('resource-loader-results', '测试 loadScript 方法...', 'info');
|
||
|
||
// 创建一个测试脚本
|
||
const testScriptContent = 'window.testLibLoaded = true;';
|
||
const blob = new Blob([testScriptContent], { type: 'application/javascript' });
|
||
const testUrl = URL.createObjectURL(blob);
|
||
|
||
loader.loadScript('test-lib', testUrl)
|
||
.then(() => {
|
||
if (window.testLibLoaded) {
|
||
logResult('resource-loader-results', '✓ loadScript 成功加载脚本', 'pass');
|
||
} else {
|
||
logResult('resource-loader-results', '✗ loadScript 加载脚本失败', 'fail');
|
||
}
|
||
|
||
// 测试缓存机制
|
||
if (loader.loaded.has('test-lib')) {
|
||
logResult('resource-loader-results', '✓ 加载的脚本已添加到缓存', 'pass');
|
||
} else {
|
||
logResult('resource-loader-results', '✗ 脚本未添加到缓存', 'fail');
|
||
}
|
||
|
||
// 测试重复加载
|
||
const startTime = Date.now();
|
||
return loader.loadScript('test-lib', testUrl).then(() => {
|
||
const loadTime = Date.now() - startTime;
|
||
if (loadTime < 10) {
|
||
logResult('resource-loader-results', '✓ 重复加载使用缓存(立即返回)', 'pass');
|
||
} else {
|
||
logResult('resource-loader-results', `⚠ 重复加载耗时 ${loadTime}ms(可能未使用缓存)`, 'fail');
|
||
}
|
||
});
|
||
})
|
||
.then(() => {
|
||
// 测试加载失败的情况
|
||
return loader.loadScript('invalid-lib', 'https://invalid-url-that-does-not-exist.com/script.js')
|
||
.then(() => {
|
||
logResult('resource-loader-results', '✗ 加载失败应该抛出错误', 'fail');
|
||
})
|
||
.catch((error) => {
|
||
if (error.message.includes('Failed to load')) {
|
||
logResult('resource-loader-results', '✓ 加载失败正确抛出错误', 'pass');
|
||
} else {
|
||
logResult('resource-loader-results', '✗ 错误信息不正确', 'fail');
|
||
}
|
||
});
|
||
})
|
||
.then(() => {
|
||
logResult('resource-loader-results', '✅ 资源加载模块测试完成', 'info');
|
||
URL.revokeObjectURL(testUrl);
|
||
})
|
||
.catch((error) => {
|
||
logResult('resource-loader-results', `✗ 测试出错: ${error.message}`, 'fail');
|
||
});
|
||
|
||
} catch (error) {
|
||
logResult('resource-loader-results', `✗ 测试出错: ${error.message}`, 'fail');
|
||
}
|
||
}
|
||
|
||
// 测试 6: 渲染优化模块
|
||
function testRenderOptimizer() {
|
||
clearResults('render-optimizer-results');
|
||
logResult('render-optimizer-results', '开始测试渲染优化模块...', 'info');
|
||
|
||
try {
|
||
// 创建实例
|
||
const optimizer = new ArgonRenderOptimizer();
|
||
logResult('render-optimizer-results', '✓ ArgonRenderOptimizer 实例创建成功', 'pass');
|
||
|
||
// 测试读写队列
|
||
let readValue = 0;
|
||
let writeValue = 0;
|
||
|
||
optimizer.read(() => {
|
||
readValue = document.body.offsetHeight; // 读取操作
|
||
logResult('render-optimizer-results', `读取操作执行,获取高度: ${readValue}px`, 'info');
|
||
});
|
||
|
||
optimizer.write(() => {
|
||
const testDiv = document.createElement('div');
|
||
testDiv.textContent = '测试写入操作';
|
||
writeValue = 1;
|
||
logResult('render-optimizer-results', '写入操作执行', 'info');
|
||
});
|
||
|
||
// 等待 requestAnimationFrame 执行
|
||
setTimeout(() => {
|
||
if (readValue > 0 && writeValue === 1) {
|
||
logResult('render-optimizer-results', '✓ 读写队列正常工作', 'pass');
|
||
} else {
|
||
logResult('render-optimizer-results', '✗ 读写队列执行失败', 'fail');
|
||
}
|
||
|
||
// 测试批量操作顺序
|
||
const operations = [];
|
||
|
||
optimizer.read(() => {
|
||
operations.push('read1');
|
||
});
|
||
|
||
optimizer.write(() => {
|
||
operations.push('write1');
|
||
});
|
||
|
||
optimizer.read(() => {
|
||
operations.push('read2');
|
||
});
|
||
|
||
optimizer.write(() => {
|
||
operations.push('write2');
|
||
});
|
||
|
||
setTimeout(() => {
|
||
const expectedOrder = ['read1', 'read2', 'write1', 'write2'];
|
||
const orderCorrect = JSON.stringify(operations) === JSON.stringify(expectedOrder);
|
||
|
||
if (orderCorrect) {
|
||
logResult('render-optimizer-results', '✓ 批量操作顺序正确(先读后写)', 'pass');
|
||
} else {
|
||
logResult('render-optimizer-results', `✗ 操作顺序错误: ${operations.join(', ')}`, 'fail');
|
||
}
|
||
|
||
// 测试 GPU 加速
|
||
const testElement = document.getElementById('test-animation-element');
|
||
|
||
optimizer.enableGPU(testElement);
|
||
const willChangeEnabled = testElement.style.willChange === 'transform, opacity';
|
||
|
||
if (willChangeEnabled) {
|
||
logResult('render-optimizer-results', '✓ enableGPU 正确设置 will-change 属性', 'pass');
|
||
} else {
|
||
logResult('render-optimizer-results', '✗ enableGPU 设置失败', 'fail');
|
||
}
|
||
|
||
optimizer.disableGPU(testElement);
|
||
const willChangeDisabled = testElement.style.willChange === 'auto';
|
||
|
||
if (willChangeDisabled) {
|
||
logResult('render-optimizer-results', '✓ disableGPU 正确移除 will-change 属性', 'pass');
|
||
} else {
|
||
logResult('render-optimizer-results', '✗ disableGPU 移除失败', 'fail');
|
||
}
|
||
|
||
// 测试错误处理
|
||
optimizer.read(() => {
|
||
throw new Error('测试错误');
|
||
});
|
||
|
||
optimizer.write(() => {
|
||
logResult('render-optimizer-results', '✓ 错误处理正常,后续操作继续执行', 'pass');
|
||
});
|
||
|
||
setTimeout(() => {
|
||
logResult('render-optimizer-results', '✅ 渲染优化模块测试完成', 'info');
|
||
}, 100);
|
||
}, 100);
|
||
}, 100);
|
||
|
||
} catch (error) {
|
||
logResult('render-optimizer-results', `✗ 测试出错: ${error.message}`, 'fail');
|
||
}
|
||
}
|
||
|
||
// 运行所有测试
|
||
function runAllTests() {
|
||
clearResults('all-tests-results');
|
||
logResult('all-tests-results', '🚀 开始运行所有测试...', 'info');
|
||
|
||
testDOMCache();
|
||
testEventManager();
|
||
testThrottle();
|
||
testDebounce();
|
||
testResourceLoader();
|
||
testRenderOptimizer();
|
||
|
||
setTimeout(() => {
|
||
logResult('all-tests-results', '✅ 所有测试已启动,请查看各模块的测试结果', 'info');
|
||
}, 500);
|
||
}
|
||
|
||
// 页面加载完成后的提示
|
||
window.addEventListener('load', () => {
|
||
console.log('Argon 性能优化模块测试页面已加载');
|
||
console.log('ArgonPerformanceConfig:', ArgonPerformanceConfig);
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|