Skip to main content

Js Request Idle Callback

Source: .agents/references/coding-standard/vercel-react-best-practices/rules/js-request-idle-callback.md

Metadata

  • title: Defer Non-Critical Work with requestIdleCallback
  • impact: MEDIUM
  • impactDescription: keeps UI responsive during background tasks
  • tags: javascript, performance, idle, scheduling, analytics

Content

Defer Non-Critical Work with requestIdleCallback

Impact: MEDIUM (keeps UI responsive during background tasks)

Use requestIdleCallback() to schedule non-critical work during browser idle periods. This keeps the main thread free for user interactions and animations, reducing jank and improving perceived performance.

Incorrect (blocks main thread during user interaction):

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

// These block the main thread immediately
analytics.track('search', { query })
saveToRecentSearches(query)
prefetchTopResults(results.slice(0, 3))
}

Correct (defers non-critical work to idle time):

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

// Defer non-critical work to idle periods
requestIdleCallback(() => {
analytics.track('search', { query })
})

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

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

With timeout for required work:

// Ensure analytics fires within 2 seconds even if browser stays busy
requestIdleCallback(
() => analytics.track('page_view', { path: location.pathname }),
{ timeout: 2000 }
)

Chunking large tasks:

function processLargeDataset(items: Item[]) {
let index = 0

function processChunk(deadline: IdleDeadline) {
// Process items while we have idle time (aim for <50ms chunks)
while (index < items.length && deadline.timeRemaining() > 0) {
processItem(items[index])
index++
}

// Schedule next chunk if more items remain
if (index < items.length) {
requestIdleCallback(processChunk)
}
}

requestIdleCallback(processChunk)
}

With fallback for unsupported browsers:

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

scheduleIdleWork(() => {
// Non-critical work
})

When to use:

  • Analytics and telemetry
  • Saving state to localStorage/IndexedDB
  • Prefetching resources for likely next actions
  • Processing non-urgent data transformations
  • Lazy initialization of non-critical features

When NOT to use:

  • User-initiated actions that need immediate feedback
  • Rendering updates the user is waiting for
  • Time-sensitive operations