Files
2026-07-13 21:36:17 +08:00

2.5 KiB

title, impact, impactDescription, tags
title impact impactDescription tags
使用 requestIdleCallback 延迟非关键任务 MEDIUM 在后台任务期间保持 UI 响应 javascript, performance, idle, scheduling, analytics

使用 requestIdleCallback 延迟非关键任务

影响等级:中等(在后台任务期间保持 UI 响应)

使用 requestIdleCallback() 在浏览器空闲时段调度非关键任务。这能让主线程腾出来处理用户交互和动画,减少卡顿,提升感知性能。

不正确的做法(在用户交互期间阻塞主线程):

function handleSearch(query: string) {
  const results = searchItems(query)
  setResults(results)

  // 这些操作会立即阻塞主线程
  analytics.track('search', { query })
  saveToRecentSearches(query)
  prefetchTopResults(results.slice(0, 3))
}

正确的做法(将非关键任务推迟到空闲时间):

function handleSearch(query: string) {
  const results = searchItems(query)
  setResults(results)

  // 将非关键任务推迟到空闲时段
  requestIdleCallback(() => {
    analytics.track('search', { query })
  })

  requestIdleCallback(() => {
    saveToRecentSearches(query)
  })

  requestIdleCallback(() => {
    prefetchTopResults(results.slice(0, 3))
  })
}

为必须执行的任务设置超时:

// 确保分析事件在 2 秒内触发,即使浏览器一直繁忙
requestIdleCallback(
  () => analytics.track('page_view', { path: location.pathname }),
  { timeout: 2000 }
)

将大任务分块处理:

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)
}

为不支持的浏览器提供降级方案:

const scheduleIdleWork = window.requestIdleCallback ?? ((cb: () => void) => setTimeout(cb, 1))

scheduleIdleWork(() => {
  // 非关键任务
})

适用场景:

  • 分析与遥测
  • 将状态保存到 localStorage/IndexedDB
  • 为可能的下一个操作预取资源
  • 处理非紧急的数据转换
  • 非关键功能的懒初始化

不适用场景:

  • 需要即时反馈的用户操作
  • 用户正在等待的渲染更新
  • 时间敏感的操作