--- title: Defer Non-Critical Work with requestIdleCallback impact: MEDIUM impactDescription: keeps UI responsive during background tasks tags: 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):** ```typescript 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):** ```typescript 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:** ```typescript // Ensure analytics fires within 2 seconds even if browser stays busy requestIdleCallback( () => analytics.track('page_view', { path: location.pathname }), { timeout: 2000 }, ); ``` **Chunking large tasks:** ```typescript 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:** ```typescript 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