深入理解 requestIdleCallback:瀏覽器空閑時段的性能優化利器

requestIdleCallback 核心作用

requestIdleCallback?是瀏覽器提供的 API,用于將非關鍵任務延遲到瀏覽器空閑時段執行,避免阻塞用戶交互、動畫等關鍵任務,從而提升頁面性能體驗。

基本語法

const handle = window.requestIdleCallback(callback[, options])

參數

  • callback:一個將在瀏覽器空閑時期被調用的函數。該回調函數接收一個參數:

    • IdleDeadline?對象,包含:

      • timeRemaining():返回當前幀剩余的空閑時間(毫秒),通常 ≤ 50ms

      • didTimeout:布爾值,表示是否因為指定的 timeout 時間已到而觸發回調

  • options(可選):配置對象

    • timeout:如果指定了 timeout,并且回調在 timeout 毫秒后還沒有被調用,則回調會在下一次有機會時被強制執行

返回值

返回一個 ID,可以傳遞給?cancelIdleCallback()?來取消回調。

配套方法

window.cancelIdleCallback(handle)

取消之前通過?requestIdleCallback()?安排的回調。?

工作原理

  1. 瀏覽器在每一幀渲染完成后會檢查是否有空閑時間

  2. 如果有空閑時間,且存在待執行的 idle 回調,則執行它們

  3. 每次 idle 回調執行時,可以通過?timeRemaining()?檢查剩余時間

  4. 如果任務未完成,可以在回調中再次調用?requestIdleCallback?繼續處理

使用示例

基本用法

function processInIdleTime(deadline) {while (deadline.timeRemaining() > 0 && tasks.length > 0) {performTask(tasks.pop());}if (tasks.length > 0) {requestIdleCallback(processInIdleTime);}
}requestIdleCallback(processInIdleTime);

帶超時的用法

requestIdleCallback(processInIdleTime, { timeout: 2000 });
// 保證在2秒內執行,即使瀏覽器一直不空閑

關鍵特性

特性說明
空閑期執行只在瀏覽器主線程空閑時運行(每幀渲染后的空閑時間)
可中斷性如果用戶開始交互,任務會被暫停
超時控制可通過?timeout?參數強制在指定時間后執行(避免長期等待)

適用場景

  1. 日志上報和分析:將非關鍵的日志發送推遲到空閑時間

  2. 預加載資源:預加載接下來可能需要的非關鍵資源

  3. 大數據處理:分塊處理大型數據集,避免界面卡頓

  4. 非關鍵UI更新:如更新界面上的輔助信息或統計數字

注意事項

  1. 不要用于關鍵任務:空閑回調可能永遠不會執行,或者執行得很晚

  2. 任務應該可分片:每次回調應該只處理一小部分工作

  3. 避免DOM操作:在空閑回調中進行DOM操作可能觸發重排/重繪

  4. 超時設置要合理:過短的 timeout 會使 API 失去意義,過長則影響體驗

瀏覽器兼容性分析

? 完全支持的瀏覽器
  • Chrome

    • 版本:47+(2015年發布)

    • 備注:包括所有基于 Chromium 的瀏覽器(Edge、Opera 等)

  • Firefox

    • 版本:55+(2017年發布)

    • 備注:在移動端和桌面端表現一致

  • Edge

    • 版本:79+(Chromium 內核版本)

?? 部分支持/行為差異的瀏覽器
  • Safari

    • 版本:部分支持(需檢測)

    • 問題:

      • iOS Safari 和 macOS Safari 實現可能不一致

      • 某些版本中?timeRemaining()?返回值不準確

? 不支持的瀏覽器
  • Internet Explorer

    • 所有版本均不支持

  • 舊版 Edge(EdgeHTML 內核)

    • 版本:18 及以下

  • Android 默認瀏覽器(4.4及以下)


兼容性風險點列表

  1. 移動端注意

    • 部分安卓 WebView(特別是 Hybrid 應用內嵌瀏覽器)可能不支持

  2. Safari 特殊性

    • 某些版本即使支持 API,空閑時間計算可能不準確

  3. 隱身模式影響

    • 部分瀏覽器在隱身模式下會限制后臺任務執行

兼容性解決方案列表

特性檢測標準寫法

const hasIdleCallback = 'requestIdleCallback' in window;

推薦降級方案

優先降級到 requestAnimationFrame(適合視覺相關任務)

其次降級到 setTimeout(callback, 0)(通用方案)

Polyfill 選擇

官方推薦的 polyfill

注意:polyfill 無法真正模擬空閑期,只是延遲執行

/*** 增強型空閑任務調度器(支持多級降級方案)* @param {Function} callback - 需要執行的回調函數,接收 deadline 對象* @param {Object} [options] - 配置選項* @param {number} [options.timeout=0] - 超時時間(毫秒)* @returns {number} 調度器ID(可用于取消)*/
function enhancedRequestIdleCallback(callback, options = {}) {// 參數有效性檢查if (typeof callback !== 'function') {throw new TypeError('回調必須是函數');}const { timeout = 0 } = options;// 原生支持檢測if ('requestIdleCallback' in window) {return window.requestIdleCallback(callback, { timeout });}// ========== 降級方案實現 ==========let id;const start = Date.now();const isVisualTask = isRelatedToVisualUpdate(callback);// 方案1:視覺相關任務使用 requestAnimationFrameif (isVisualTask && 'requestAnimationFrame' in window) {id = window.requestAnimationFrame(() => {callback({timeRemaining: () => Math.max(0, 16.6 - (Date.now() - start)),didTimeout: Date.now() - start >= timeout});});}// 方案2:通用任務使用 setTimeoutelse {// 計算合理延遲時間(避免過度消耗資源)const delay = calculateSafeDelay(isVisualTask);id = window.setTimeout(() => {callback({timeRemaining: () => 1, // 模擬1ms剩余時間didTimeout: true       // 降級模式下總是觸發超時});}, delay);}// 添加超時強制觸發機制if (timeout > 0) {const timeoutId = setTimeout(() => {callback({timeRemaining: () => 0,didTimeout: true});clearTimeout(id);}, timeout);// 返回復合ID用于取消return { rId: id, tId: timeoutId };}return id;
}/*** 取消空閑任務調度* @param {number|Object} id - 調度器返回的ID*/
function enhancedCancelIdleCallback(id) {if ('cancelIdleCallback' in window) {window.cancelIdleCallback(id);return;}// 處理復合ID(超時場景)if (typeof id === 'object') {clearTimeout(id.tId);id = id.rId;}// 根據降級方案取消if ('cancelAnimationFrame' in window) {window.cancelAnimationFrame(id);} else {clearTimeout(id);}
}// ========== 工具函數 ==========
/*** 判斷任務是否與視覺更新相關* (根據常見DOM API使用模式推測)*/
function isRelatedToVisualUpdate(fn) {const fnStr = fn.toString();return /(offset|scroll|client|getBounding|style)/.test(fnStr);
}/*** 計算安全延遲時間* 視覺任務:下一幀時間(16.6ms)* 非視覺任務:分級延遲(0-50ms隨機)*/
function calculateSafeDelay(isVisual) {return isVisual ? 16 : Math.min(50, Math.floor(Math.random() * 50));
}// ========== 使用示例 ==========
// 示例任務
function backgroundTask(deadline) {while (deadline.timeRemaining() > 0) {// 執行任務分片...}if (hasMoreWork) {enhancedRequestIdleCallback(backgroundTask);}
}// 啟動任務
const taskId = enhancedRequestIdleCallback(backgroundTask, { timeout: 2000 });// 取消任務
// enhancedCancelIdleCallback(taskId);

注意事項

避免在回調中修改 DOM(可能觸發重排)

空閑時間不保證,任務應有中斷/恢復機制

耗時任務應使用 Web Worker

requestIdleCallback的詳細介紹和示例代碼

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>requestIdleCallback 示例與兼容性處理</title>
</head>
<body>
<h1>requestIdleCallback 演示</h1>
<div id="output"></div><script>/*** 兼容性處理:如果原生不支持 requestIdleCallback,* 使用 setTimeout 實現降級方案*/window.requestIdleCallback = window.requestIdleCallback || function(cb) {// 降級方案:用 50ms 延遲模擬空閑時段let start = Date.now();return setTimeout(function() {cb({didTimeout: false,timeRemaining: function() {// 確保至少留出 1ms 時間return Math.max(0, 50 - (Date.now() - start));}});}, 1);};/*** 分塊任務處理器* @param {Array} taskList - 要處理的任務數組* @param {Function} processor - 單個任務處理函數* @param {number} chunkSize - 每次處理的任務數(默認 10)*/function processTasksInIdle(taskList, processor, chunkSize = 10) {let index = 0;function doChunk(deadline) {// 當剩余時間 > 0 或超時前處理任務while ((deadline.timeRemaining() > 0 || deadline.didTimeout) &&index < taskList.length) {// 每次處理指定數量的任務const tasksToProcess = taskList.slice(index, index + chunkSize);tasksToProcess.forEach(task => processor(task));index += chunkSize;// 更新頁面顯示進度updateProgress(index);}// 如果還有剩余任務,繼續調度if (index < taskList.length) {// 使用超時參數 100ms 保證即使不空閑也會執行requestIdleCallback(doChunk, { timeout: 100 });}}// 初始調用requestIdleCallback(doChunk, { timeout: 100 });}// 示例:創建 500 個元素的列表(模擬大量任務)const dummyTasks = new Array(500).fill(null).map((_, i) => ({id: i + 1,content: `Item ${i + 1}`}));// 任務處理函數(模擬DOM操作)function handleTask(task) {const div = document.createElement('div');div.textContent = task.content;// 這里可以添加更復雜的操作}// 更新進度顯示function updateProgress(processedCount) {const output = document.getElementById('output');output.textContent = `已處理 ${processedCount}/${dummyTasks.length} 項任務`;}// 啟動任務處理(頁面加載完成后)window.addEventListener('load', () => {processTasksInIdle(dummyTasks, handleTask, 10); // 每次處理10個});
</script><!-- 兼容性提示 -->
<script>// 檢測是否原生支持if (!window.requestIdleCallback) {const warn = document.createElement('p');warn.style.color = 'red';warn.textContent = '當前瀏覽器不支持 requestIdleCallback,已使用 setTimeout 降級方案';document.body.appendChild(warn);}
</script>
</body>
</html>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/81445.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/81445.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/81445.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

51單片機——交通指示燈控制器設計

設計目標 1、設計一交通燈控制&#xff0c;控制東西方向的紅、黃、綠燈和南北方向的紅、黃、綠燈。 2、可手動控制和自動控制&#xff0c;設置兩個輸入控制開關。 手動/自動開關&#xff0c;通過P11的按鍵輸入控制 3、手動&#xff1a;設置開關P11&#xff0c;兩種情況&#x…

神經網絡語言模型(前饋神經網絡語言模型)

神經網絡語言模型 什么是神經網絡&#xff1f;神經網絡的基本結構是什么&#xff1f;輸入層隱藏層輸出層 神經網絡為什么能解決問題&#xff1f;通用近似定理為什么需要權重和偏置&#xff1f;為什么需要激活函數&#xff1f;權重是如何確定的&#xff1f;1. 窮舉2. 反向傳播主…

信息系統項目管理師高級-軟考高項案例分析備考指南(2023年案例分析)

個人筆記整理---僅供參考 計算題 案例分析里的計算題就是進度、掙值分析、預測技術。主要考査的知識點有:找關鍵路徑、求總工期、自由時差、總時差、進度壓縮資源平滑、掙值計算、預測計算。計算題是一定要拿下的&#xff0c;做計算題要保持頭腦清晰&#xff0c;認真讀題把PV、…

unordered_map和unordered的介紹和使用

目錄 unordered系列關聯式容器 unordered_map unordered_map的接口說明 unordered_map的定義方式 unordered_map接口的使用 unordered_map的容量 unordered_map的迭代器 unordered_map的元素訪問 unordered_map的查詢 unordered_map的修改操作 unordered_multimap u…

設計模式7大原則與UML類圖詳解

設計模式7大原則與UML類圖詳解 引言 &#x1f31f; 在軟件工程領域&#xff0c;設計模式和UML&#xff08;統一建模語言&#xff09;是提高代碼質量、增強系統可維護性的重要工具。設計模式提供了解決軟件設計中常見問題的通用方案&#xff0c;而UML則為我們提供了一種可視化的…

計算機視覺與深度學習 | Python實現ARIMA-LSTM時間序列預測(完整源碼和數據)

ARIMA-LSTM混合模型 1. 環境準備2. 數據生成(示例數據)3. 數據預處理4. ARIMA建模5. LSTM殘差建模6. 混合預測7. 結果可視化完整代碼說明1. **數據生成**2. **ARIMA建模**3. **LSTM殘差建模**4. **混合預測**5. **性能評估**參數調優建議擴展方向典型輸出以下是使用Python實現…

Docker部署單節點Elasticsearch

1.Docker部署單節點ES 1.前置條件 配置內核參數 echo "vm.max_map_count262144" >> /etc/sysctl.conf sysctl -w vm.max_map_count262144準備密碼 本文所有涉及密碼的配置&#xff0c;均使用通用密碼 Zzwl2024。 生產環境&#xff0c;請用密碼生成器生成20…

pe文件二進制解析(用c/c++解析一個二進制pe文件)

pe文件二進制解析 c解析pe文件控制臺版本 #include<iostream> #include<windows.h> #include<vector>/*RVA&#xff08;相對虛擬地址&#xff09;與FOA&#xff08;文件偏移地址&#xff09;的轉換1.得到 的值&#xff1a;內存地址 - ImageBase2.判斷是否位…

融智學視域下的系統性認知增強框架——基于文理工三類AI助理賦能HI四階躍遷路徑

融智學視域下的系統性認知增強框架 ——基于文理工三類AI助理賦能HI四階躍遷路徑 一、如何排除50個認知偏差&#xff1a;消除50類偏差的精準矯正系統 1. 技術架構 文科AI&#xff1a; 構建文化語義場&#xff08;Cultural Semantic Field, CSF&#xff09;&#xff0c;通過…

MMDetection環境安裝配置

MMDetection 支持在 Linux&#xff0c;Windows 和 macOS 上運行。它需要 Python 3.7 以上&#xff0c;CUDA 9.2 以上和 PyTorch 1.8 及其以上。 MMDetection 至今也一直更新很多個版本了&#xff0c;但是對于最新的pytorch版本仍然不支持&#xff0c;我安裝的時候仍然多次遇到m…

如何實現k8s高可用

一、控制平面高可用設計 多主節點部署 ? API Server 冗余&#xff1a;部署至少 3 個 Master 節點&#xff0c;每個節點運行獨立的 API Server&#xff0c;通過負載均衡器&#xff08;如 Nginx、HAProxy、云廠商 LB&#xff09;對外提供統一入口。 ? 選舉機制&#xff1a;Sche…

記錄心態和工作變化

忙中帶閑的工作 其實工作挺忙的, 總是在趕各種功能點. 好巧的是iOS那邊因為上架的問題耽擱了一些時間, 從而讓Android的進度有了很大的調整空間. 更巧的是后端那邊因為對客戶端的需求不是很熟悉, 加上Android海外這塊的業務他也是第一次接觸. 所以需要給他留一些時間把各個環節…

JVM 雙親委派機制

一、從 JDK 到 JVM&#xff1a;Java 運行環境的基石 在 Java 開發領域&#xff0c;JDK&#xff08;Java Development Kit&#xff09;是開發者的核心工具包。它不僅包含了編譯 Java 代碼的工具&#xff08;如 javac&#xff09;&#xff0c;還內置了 JRE&#xff08;Java Run…

java開發之異常

一 結構 Throwable分為Exception和error Exception分為RuntimeException&#xff08;運行時異常&#xff09;和其他異常 主動拋出運行時異常和非運行時異常的區別 1、throw RuntimeException&#xff08;或運行時異常的子類&#xff09; 編譯時不會報錯。 2、throw Excepti…

MySQL 中 JOIN 和子查詢的區別與使用場景

目錄 一、JOIN:表連接1.1 INNER JOIN:內連接1.2 LEFT JOIN:左連接1.3 RIGHT JOIN:右連接1.4 FULL JOIN:全連接二、子查詢:嵌套查詢2.1 WHERE 子句中的子查詢2.2 FROM 子句中的子查詢2.3 SELECT 子句中的子查詢三、JOIN 和子查詢的區別3.1 功能差異3.2 性能差異3.3 使用場…

2025年第三屆盤古石杯初賽(智能冰箱,監控部分)

前言 所以去哪里可以取到自己家里的智能家居數據呢&#xff1f;&#xff1f;&#xff1f;&#xff1f; IOT物聯網取證 1、分析冰箱&#xff0c;請問智能冰箱的品牌&#xff1f; [答案格式&#xff1a;xiaomi] Panasonic2、請問智能冰箱的型號&#xff1f; [答案格式&#x…

【強化學習】強化學習算法 - 馬爾可夫決策過程

文章目錄 馬爾可夫決策過程 (Markov Decision Process, MDP)1. MDP 原理介紹2. MDP 建模/實現步驟3. MDP 示例&#xff1a;簡單網格世界 (Grid World) 馬爾可夫決策過程 (Markov Decision Process, MDP) 1. MDP 原理介紹 馬爾可夫決策過程 (MDP) 是強化學習 (Reinforcement L…

用戶現場不支持路由映射,如何快速將安防監控EasyCVR視頻匯聚平臺映射到公網?

一、方案背景? 隨著數字化安防與智能交通管理發展&#xff0c;視頻監控遠程管理需求激增。EasyCVR作為專業視頻融合平臺&#xff0c;具備多協議接入等核心功能&#xff0c;是智能監控的重要工具。但實際部署中&#xff0c;當EasyCVR處于內網且路由器無法進行端口映射時&#…

MODBUS RTU調試助手使用方法詳解

一、軟件簡介 485調試助手是一款常用的串口通信調試工具&#xff0c;專門用于RS-485總線設備的測試、調試和通信監控。它支持多種串口參數設置&#xff0c;提供數據收發功能&#xff0c;是工業現場調試的必備工具之一。 二、軟件安裝與啟動 1. 系統要求 Windows 7/10/11操作…

ECMAScript 2018(ES2018):異步編程與正則表達式的深度進化

1.版本背景與發布 發布時間&#xff1a;2018年6月&#xff0c;由ECMA International正式發布&#xff0c;標準編號為ECMA-262 9th Edition。歷史意義&#xff1a;作為ES6之后的第三次年度更新&#xff0c;ES2018聚焦于異步編程、正則表達式和對象操作的標準化&#xff0c;推動…