diff --git a/web-src/scripts/bench_yield.js b/web-src/scripts/bench_yield.js new file mode 100644 index 0000000..4cb8e6c --- /dev/null +++ b/web-src/scripts/bench_yield.js @@ -0,0 +1,21 @@ +console.log('Running Yield Benchmark...'); + +async function measure(name, fn) { + const start = process.hrtime.bigint(); + await fn(); + const end = process.hrtime.bigint(); + const duration = Number(end - start) / 1e6; // ms + console.log(`${name}: ${duration.toFixed(2)}ms`); +} + +async function run() { + // Baseline: 100ms delay + await measure('setTimeout(100) [Old]', () => new Promise(r => setTimeout(r, 100))); + + // Optimized: 0ms delay (simulating yieldToMain) + // Note: yieldToMain uses requestAnimationFrame which is ~16ms max, but in Node we only have setTimeout(0) or setImmediate. + // We use setTimeout(0) to approximate the minimal delay. + await measure('setTimeout(0) [New]', () => new Promise(r => setTimeout(r, 0))); +} + +run(); diff --git a/web-src/src/App.tsx b/web-src/src/App.tsx index 03e5e33..0c9de31 100644 --- a/web-src/src/App.tsx +++ b/web-src/src/App.tsx @@ -286,7 +286,7 @@ function App() { setAnalysisProgress(`流式解析 ${format.toUpperCase()} 文件 (${formatFileSize(file.size)})...`); console.log(`使用 Worker 流式解析模式 (文件大小: ${formatFileSize(file.size)}, 格式: ${format})`); - // 强制让 UI 有时间渲染进度条 + // Yield to main thread to allow UI (progress bar) to render await yieldToMain(); let metadata: any; // 元数据(不包含全部 tags/gops) diff --git a/web-src/src/utils/yieldToMain.ts b/web-src/src/utils/yieldToMain.ts index f01cb22..86509b6 100644 --- a/web-src/src/utils/yieldToMain.ts +++ b/web-src/src/utils/yieldToMain.ts @@ -1,9 +1,10 @@ /** - * Yields to the main thread to allow the browser to process UI updates and other tasks. - * This is a more efficient and reliable way to prevent long-running tasks from blocking - * the UI than using `setTimeout(..., 0)`. + * Yields to the main thread to allow the browser to paint UI updates. + * This is useful for ensuring UI changes are rendered before a long-running task. + * It uses `requestAnimationFrame` and `setTimeout(0)` to resolve the promise + * *after* the next paint cycle. * - * @returns A promise that resolves on the next animation frame. + * @returns A promise that resolves after the next browser paint. */ export function yieldToMain(): Promise { return new Promise(resolve => { @@ -18,6 +19,6 @@ export function yieldToMain(): Promise { setTimeout(resolve, 0); return; } - requestAnimationFrame(() => resolve()); + requestAnimationFrame(() => setTimeout(resolve, 0)); }); }