🟢 What —— 它是什么?
requestIdleCallback(callback[, options])
是瀏覽器提供的一個 API,用來在主線程空閑時執行一些優先級不高的任務。
它的特點:
- 異步執行:不會打斷關鍵的渲染、交互、動畫。
- 節省性能:只在瀏覽器判斷“有空”的時候執行。
- 可控時限:通過
options.timeout
可以設置最遲必須執行的時間。
執行時,瀏覽器會傳遞一個 IdleDeadline 對象 給回調:
timeRemaining()
:返回當前幀剩余的空閑時間(毫秒)。didTimeout
:是否因為超時而強制執行。
🟢 Why —— 為什么需要它?
在 Web 應用里,任務往往有兩類:
-
高優先級任務
- UI 渲染、用戶交互、動畫。
- 必須馬上執行,否則就會“卡頓”。
-
低優先級任務
- 數據預加載、日志上報、分析埋點、緩存清理。
- 不影響用戶體驗,可以“等一等”。
👉 傳統做法(如 setTimeout
)不夠聰明,因為它只看時間,不知道瀏覽器忙不忙。
而 requestIdleCallback
能感知瀏覽器是否有空閑時間,在不阻塞渲染的情況下,把這些低優先級任務“插隊”執行。
好處:
- 提升流暢度:避免任務和渲染搶 CPU。
- 提升效率:利用“碎片時間”做事,不浪費。
- 適合漸進加載:比如逐步渲染一大段數據。
🟢 How —— 怎么用?
基本用法
function heavyTask(deadline) {while (deadline.timeRemaining() > 0 && tasks.length > 0) {const task = tasks.shift();process(task);}// 任務沒做完,繼續安排if (tasks.length > 0) {requestIdleCallback(heavyTask);}
}requestIdleCallback(heavyTask);
解釋:
- 每一幀有空閑時間就干活。
- 干不完就遞歸丟到下一個 idle。
- 避免一次性干太多,阻塞 UI。
設置超時
有時候,任務必須在某個時間點前完成:
requestIdleCallback((deadline) => {if (deadline.timeRemaining() > 0 || deadline.didTimeout) {sendAnalyticsData();}
}, { timeout: 2000 });
👉 即使 2 秒內瀏覽器都很忙,也會強制執行。
實際應用場景
-
日志 & 埋點
requestIdleCallback(() => {sendLogBuffer(); });
-
漸進渲染列表(虛擬列表之前的簡單方式)
let i = 0; function renderChunk(deadline) {while (deadline.timeRemaining() > 0 && i < bigList.length) {renderItem(bigList[i++]);}if (i < bigList.length) requestIdleCallback(renderChunk); } requestIdleCallback(renderChunk);
-
預加載資源
requestIdleCallback(() => {new Image().src = "/next-page-banner.jpg"; });
?? 注意事項
- 兼容性:Safari 不支持,需要
setTimeout
polyfill。 - 不適合實時任務:比如動畫、UI 更新,不應該放進來。
- 有點“玄學”:空閑時間由瀏覽器決定,執行時機不可預測。