2.6 KiB
2.6 KiB
title, impact, impactDescription, tags
| title | impact | impactDescription | tags |
|---|---|---|---|
| Defer Non-Critical Work with requestIdleCallback | MEDIUM | keeps UI responsive during background tasks | javascript, performance, idle, scheduling, analytics |
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