paper-burner/tests/performance/test-async-tasks.html

375 lines
13 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>验证:页面隐藏不影响异步任务</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
padding: 40px;
background: #f5f5f5;
}
.container {
max-width: 900px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
h1 {
color: #333;
margin-bottom: 20px;
}
.warning {
background: #fff3cd;
border-left: 4px solid #ffc107;
padding: 15px;
margin: 20px 0;
border-radius: 4px;
}
.info {
background: #d1ecf1;
border-left: 4px solid #17a2b8;
padding: 15px;
margin: 20px 0;
border-radius: 4px;
}
.success {
background: #d4edda;
border-left: 4px solid #28a745;
padding: 15px;
margin: 20px 0;
border-radius: 4px;
}
button {
padding: 12px 24px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
margin: 10px 10px 10px 0;
}
button:hover {
background: #0056b3;
}
.log {
background: #1e1e1e;
color: #d4d4d4;
padding: 20px;
border-radius: 4px;
font-family: 'Courier New', monospace;
font-size: 14px;
max-height: 400px;
overflow-y: auto;
margin-top: 20px;
}
.log-entry {
margin-bottom: 8px;
padding: 4px 0;
}
.log-entry.info { color: #4FC3F7; }
.log-entry.success { color: #4CAF50; font-weight: bold; }
.log-entry.error { color: #EF5350; }
.log-entry.warning { color: #FFA726; }
.result {
font-size: 18px;
font-weight: bold;
padding: 20px;
text-align: center;
border-radius: 4px;
margin: 20px 0;
}
.result.pass {
background: #d4edda;
color: #155724;
}
.result.fail {
background: #f8d7da;
color: #721c24;
}
</style>
</head>
<body>
<div class="container">
<h1>🧪 验证:页面隐藏不影响异步任务</h1>
<div class="warning">
<strong>⚠️ 重要说明</strong><br>
本测试证明:即使页面隐藏,<strong>fetch()、Promise、async/await</strong> 等异步任务<strong>仍然正常执行</strong>
<br>我们的优化只影响了 <code>setInterval</code> 轮询,不影响核心业务。
</div>
<div class="info">
<strong>📋 测试步骤</strong><br>
1. 点击下面的按钮开始模拟翻译任务<br>
2. <strong>立即切换到其他标签页</strong>(这会触发页面隐藏)<br>
3. 等待 3-5 秒后切回来<br>
4. 查看结果:任务应该已经完成 ✅
</div>
<h2>测试 1: 模拟翻译 API 调用</h2>
<button onclick="testTranslationAPI()">🔄 开始模拟翻译3秒</button>
<button onclick="testMultipleAPIs()">🔄 模拟多个并发翻译5秒</button>
<h2>测试 2: 模拟 AI 对话</h2>
<button onclick="testAIChatAPI()">💬 开始模拟AI对话3秒</button>
<h2>测试 3: 对比 setInterval我们优化的部分</h2>
<button onclick="testSetInterval()">⏱️ 启动定时器(观察页面隐藏时的行为)</button>
<button onclick="stopSetInterval()">⏹️ 停止定时器</button>
<div id="result"></div>
<div class="log" id="log"></div>
</div>
<script>
const logEl = document.getElementById('log');
const resultEl = document.getElementById('result');
function log(message, type = 'info') {
const entry = document.createElement('div');
entry.className = `log-entry ${type}`;
const time = new Date().toLocaleTimeString();
entry.textContent = `[${time}] ${message}`;
logEl.appendChild(entry);
logEl.scrollTop = logEl.scrollHeight;
console.log(`[${type.toUpperCase()}] ${message}`);
}
function clearLog() {
logEl.innerHTML = '';
resultEl.innerHTML = '';
}
// 监听页面可见性变化
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
log('🔒 页面已隐藏(切换到其他标签页)', 'warning');
} else {
log('👁️ 页面可见(切回当前标签页)', 'info');
}
});
// ================================================
// 测试 1: 模拟翻译 API
// ================================================
async function testTranslationAPI() {
clearLog();
log('=== 开始测试:模拟翻译 API ===', 'info');
log('⚠️ 请在 3 秒内切换到其他标签页!', 'warning');
const startTime = Date.now();
// 模拟翻译 API 调用3秒延迟
try {
log('📤 发送翻译请求...', 'info');
// 使用真实的 Promise模拟网络请求
const result = await new Promise((resolve) => {
setTimeout(() => {
resolve({
success: true,
translatedText: '这是翻译后的文本',
pageHiddenDuringTranslation: false
});
}, 3000);
});
const endTime = Date.now();
const elapsed = ((endTime - startTime) / 1000).toFixed(1);
log('✅ 翻译完成!', 'success');
log(`⏱️ 耗时: ${elapsed}`, 'info');
log(`📥 结果: ${result.translatedText}`, 'success');
// 显示结果
resultEl.innerHTML = `
<div class="result pass">
✅ 测试通过!<br>
即使页面被隐藏,翻译任务仍然完成了!<br>
<small>耗时: ${elapsed} 秒</small>
</div>
`;
log('💡 结论fetch() / Promise 不受页面隐藏影响', 'success');
} catch (error) {
log(`❌ 错误: ${error.message}`, 'error');
resultEl.innerHTML = `
<div class="result fail">
❌ 测试失败!<br>
${error.message}
</div>
`;
}
}
// ================================================
// 测试 2: 模拟多个并发翻译
// ================================================
async function testMultipleAPIs() {
clearLog();
log('=== 开始测试:多个并发翻译 ===', 'info');
log('⚠️ 请在 5 秒内切换到其他标签页!', 'warning');
const startTime = Date.now();
// 模拟 3 个并发翻译任务
const tasks = [
simulateTranslation('段落 1', 2000),
simulateTranslation('段落 2', 3000),
simulateTranslation('段落 3', 4000)
];
try {
log('📤 发送 3 个并发翻译请求...', 'info');
const results = await Promise.all(tasks);
const endTime = Date.now();
const elapsed = ((endTime - startTime) / 1000).toFixed(1);
log('✅ 所有翻译完成!', 'success');
log(`⏱️ 总耗时: ${elapsed}`, 'info');
results.forEach((result, i) => {
log(`📥 结果 ${i + 1}: ${result}`, 'success');
});
resultEl.innerHTML = `
<div class="result pass">
✅ 测试通过!<br>
${results.length} 个并发翻译任务都完成了!<br>
<small>总耗时: ${elapsed} 秒</small>
</div>
`;
log('💡 结论:多个异步任务可以并发执行,不受页面隐藏影响', 'success');
} catch (error) {
log(`❌ 错误: ${error.message}`, 'error');
}
}
async function simulateTranslation(text, delay) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(`${text} (已翻译)`);
}, delay);
});
}
// ================================================
// 测试 3: 模拟 AI 对话
// ================================================
async function testAIChatAPI() {
clearLog();
log('=== 开始测试:模拟 AI 对话 ===', 'info');
log('⚠️ 请在 3 秒内切换到其他标签页!', 'warning');
const startTime = Date.now();
try {
log('💬 发送 AI 对话请求...', 'info');
// 模拟 AI API 调用
const result = await new Promise((resolve) => {
setTimeout(() => {
resolve({
message: '这是 AI 的回复内容',
tokens: 150
});
}, 3000);
});
const endTime = Date.now();
const elapsed = ((endTime - startTime) / 1000).toFixed(1);
log('✅ AI 回复完成!', 'success');
log(`⏱️ 耗时: ${elapsed}`, 'info');
log(`💬 回复: ${result.message}`, 'success');
resultEl.innerHTML = `
<div class="result pass">
✅ 测试通过!<br>
AI 对话在页面隐藏时仍然正常完成!<br>
<small>耗时: ${elapsed} 秒</small>
</div>
`;
log('💡 结论AI 对话 API 不受页面隐藏影响', 'success');
} catch (error) {
log(`❌ 错误: ${error.message}`, 'error');
}
}
// ================================================
// 测试 4: setInterval对比
// ================================================
let intervalId = null;
let intervalCount = 0;
function testSetInterval() {
if (intervalId) {
log('⚠️ 定时器已在运行', 'warning');
return;
}
clearLog();
log('=== 开始测试setInterval 行为(对比) ===', 'info');
log('🔄 定时器启动(每秒执行一次)', 'info');
log('⚠️ 请切换标签页观察行为', 'warning');
intervalCount = 0;
intervalId = setInterval(() => {
intervalCount++;
// 检查页面是否隐藏
if (document.hidden) {
log(`⏭️ 跳过执行(页面隐藏,计数: ${intervalCount}`, 'warning');
// 这就是我们在 annotations_summary_modal.js 中做的优化
} else {
log(`✓ 正常执行(页面可见,计数: ${intervalCount}`, 'success');
}
}, 1000);
log('💡 说明:这就是我们的优化逻辑 - 页面隐藏时跳过执行', 'info');
log('💡 但 fetch() 等异步任务不会被跳过!', 'success');
}
function stopSetInterval() {
if (!intervalId) {
log('⚠️ 定时器未运行', 'warning');
return;
}
clearInterval(intervalId);
intervalId = null;
log(`⏹️ 定时器已停止(总计执行 ${intervalCount} 次)`, 'info');
}
// ================================================
// 页面加载时的提示
// ================================================
window.addEventListener('load', () => {
log('🚀 测试工具已加载', 'info');
log('💡 提示:测试过程中请切换标签页来验证异步任务不受影响', 'info');
});
// 页面卸载时清理
window.addEventListener('beforeunload', () => {
if (intervalId) {
clearInterval(intervalId);
}
});
</script>
</body>
</html>