--- title: 使用 requestIdleCallback 延迟非关键任务 impact: MEDIUM impactDescription: 在后台任务期间保持 UI 响应 tags: javascript, performance, idle, scheduling, analytics --- ## 使用 requestIdleCallback 延迟非关键任务 **影响等级:中等(在后台任务期间保持 UI 响应)** 使用 `requestIdleCallback()` 在浏览器空闲时段调度非关键任务。这能让主线程腾出来处理用户交互和动画,减少卡顿,提升感知性能。 **不正确的做法(在用户交互期间阻塞主线程):** ```typescript function handleSearch(query: string) { const results = searchItems(query) setResults(results) // 这些操作会立即阻塞主线程 analytics.track('search', { query }) saveToRecentSearches(query) prefetchTopResults(results.slice(0, 3)) } ``` **正确的做法(将非关键任务推迟到空闲时间):** ```typescript function handleSearch(query: string) { const results = searchItems(query) setResults(results) // 将非关键任务推迟到空闲时段 requestIdleCallback(() => { analytics.track('search', { query }) }) requestIdleCallback(() => { saveToRecentSearches(query) }) requestIdleCallback(() => { prefetchTopResults(results.slice(0, 3)) }) } ``` **为必须执行的任务设置超时:** ```typescript // 确保分析事件在 2 秒内触发,即使浏览器一直繁忙 requestIdleCallback( () => analytics.track('page_view', { path: location.pathname }), { timeout: 2000 } ) ``` **将大任务分块处理:** ```typescript function processLargeDataset(items: Item[]) { let index = 0 function processChunk(deadline: IdleDeadline) { // 在空闲时间内处理任务(目标:每块 < 50ms) while (index < items.length && deadline.timeRemaining() > 0) { processItem(items[index]) index++ } // 如果还有剩余任务,调度下一块 if (index < items.length) { requestIdleCallback(processChunk) } } requestIdleCallback(processChunk) } ``` **为不支持的浏览器提供降级方案:** ```typescript const scheduleIdleWork = window.requestIdleCallback ?? ((cb: () => void) => setTimeout(cb, 1)) scheduleIdleWork(() => { // 非关键任务 }) ``` **适用场景:** - 分析与遥测 - 将状态保存到 localStorage/IndexedDB - 为可能的下一个操作预取资源 - 处理非紧急的数据转换 - 非关键功能的懒初始化 **不适用场景:** - 需要即时反馈的用户操作 - 用户正在等待的渲染更新 - 时间敏感的操作