RequestldleCallback

news/2025/10/14 11:55:42/文章来源:https://www.cnblogs.com/amulong1237/p/19140368

requestIdleCallback

requestIdleCallback 是一个浏览器API,允许开发者在浏览器空闲时期执行后台或低优先级的任务,而不会影响关键的用户交互和动画性能。

1. 基本概念

工作原理

// 基本语法
const handle = requestIdleCallback(callback[, options])// 取消回调
cancelIdleCallback(handle)

基本使用

// 简单的空闲回调
requestIdleCallback(function(deadline) {// deadline 对象包含:// - didTimeout: boolean - 回调是否因超时而被执行// - timeRemaining(): function - 返回当前帧剩余的时间(毫秒)while (deadline.timeRemaining() > 0) {// 执行一些低优先级任务performLowPriorityWork();}// 如果还有未完成的工作,可以再次请求if (hasMoreWork) {requestIdleCallback(arguments.callee);}
});

2. 详细用法

deadline 对象详解

requestIdleCallback(function(deadline) {console.log('是否超时:', deadline.didTimeout);console.log('剩余时间:', deadline.timeRemaining(), 'ms');// timeRemaining() 最大返回50ms,确保不阻塞用户交互const timeRemaining = deadline.timeRemaining();if (timeRemaining > 0) {// 有时间可以执行任务processBatchOfItems();}
});

带选项的调用

// 设置超时时间(毫秒)
requestIdleCallback(function(deadline) {if (deadline.didTimeout) {// 因超时触发,需要尽快完成工作processWorkQuickly();} else {// 正常空闲时期,可以按部就班工作processWorkNormally(deadline);}},{ timeout: 2000 } // 2秒后即使不空闲也执行
);

3. 实际应用场景

场景1:数据预处理

class DataPreprocessor {constructor() {this.pendingWork = [];this.isProcessing = false;}schedulePreprocessing(dataChunks) {this.pendingWork.push(...dataChunks);if (!this.isProcessing) {this.startProcessing();}}startProcessing() {this.isProcessing = true;requestIdleCallback((deadline) => {this.processBatch(deadline);});}processBatch(deadline) {while (this.pendingWork.length > 0 && deadline.timeRemaining() > 0) {const chunk = this.pendingWork.shift();this.preprocessChunk(chunk);}if (this.pendingWork.length > 0) {// 还有工作,继续调度requestIdleCallback((deadline) => {this.processBatch(deadline);});} else {this.isProcessing = false;}}preprocessChunk(chunk) {// 模拟数据预处理console.log('处理数据块:', chunk);// 实际可能是:数据清洗、格式转换、计算等}
}// 使用示例
const preprocessor = new DataPreprocessor();
preprocessor.schedulePreprocessing([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

场景2:日志批量发送

class LazyLogger {constructor() {this.logQueue = [];this.isScheduled = false;}log(message) {this.logQueue.push({message,timestamp: Date.now()});this.scheduleFlush();}scheduleFlush() {if (this.isScheduled || this.logQueue.length === 0) {return;}this.isScheduled = true;requestIdleCallback((deadline) => {this.flushLogs(deadline);},{ timeout: 5000 } // 最多等待5秒);}flushLogs(deadline) {const batch = [];while (this.logQueue.length > 0 && (deadline.timeRemaining() > 0 || deadline.didTimeout)) {batch.push(this.logQueue.shift());// 限制单次批量大小if (batch.length >= 50) break;}if (batch.length > 0) {this.sendToServer(batch);}if (this.logQueue.length > 0) {this.scheduleFlush();} else {this.isScheduled = false;}}sendToServer(logs) {// 模拟发送到服务器console.log('发送日志到服务器:', logs);// fetch('/api/logs', { method: 'POST', body: JSON.stringify(logs) })}
}// 使用示例
const logger = new LazyLogger();
logger.log('用户登录');
logger.log('页面浏览');
logger.log('按钮点击');

场景3:DOM更新优化

class LazyDOMUpdater {constructor(container) {this.container = container;this.pendingUpdates = [];this.isUpdating = false;}scheduleUpdate(element, newContent) {this.pendingUpdates.push({ element, newContent });if (!this.isUpdating) {this.startUpdates();}}startUpdates() {this.isUpdating = true;requestIdleCallback((deadline) => {this.processUpdates(deadline);});}processUpdates(deadline) {const fragment = document.createDocumentFragment();let updatesProcessed = 0;while (this.pendingUpdates.length > 0 && deadline.timeRemaining() > 0) {const update = this.pendingUpdates.shift();this.applyUpdate(fragment, update);updatesProcessed++;// 限制单批次更新数量if (updatesProcessed >= 10) break;}// 一次性更新DOMthis.container.appendChild(fragment);if (this.pendingUpdates.length > 0) {requestIdleCallback((deadline) => {this.processUpdates(deadline);});} else {this.isUpdating = false;}}applyUpdate(fragment, update) {const div = document.createElement('div');div.textContent = update.newContent;fragment.appendChild(div);}
}// 使用示例
const container = document.getElementById('content');
const updater = new LazyDOMUpdater(container);// 批量调度更新
for (let i = 0; i < 100; i++) {updater.scheduleUpdate(null, `内容项 ${i}`);
}

4. 高级用法和最佳实践

结合 Promise 使用

function idlePromise(timeout) {return new Promise((resolve) => {requestIdleCallback((deadline) => {resolve(deadline);},timeout ? { timeout } : undefined);});
}// 使用 async/await
async function processHeavyWork() {const deadline = await idlePromise(1000);if (deadline.timeRemaining() > 0 || deadline.didTimeout) {// 执行繁重任务await heavyCalculation();}
}

性能监控

function monitoredIdleCallback(callback, options) {const startTime = performance.now();return requestIdleCallback((deadline) => {const callbackStart = performance.now();const queueTime = callbackStart - startTime;callback(deadline);const executionTime = performance.now() - callbackStart;// 监控指标console.log(`队列等待时间: ${queueTime}ms`);console.log(`执行时间: ${executionTime}ms`);console.log(`剩余时间: ${deadline.timeRemaining()}ms`);// 可以发送到监控系统if (executionTime > 50) {console.warn('空闲回调执行时间过长');}}, options);
}

错误处理

function safeIdleCallback(callback, options) {return requestIdleCallback((deadline) => {try {callback(deadline);} catch (error) {console.error('空闲回调执行出错:', error);// 错误上报reportError(error);}}, options);
}// 使用安全版本
safeIdleCallback((deadline) => {// 可能出错的代码riskyOperation();
});

5. 兼容性和回退方案

// 兼容性检查
const supportsIdleCallback = 'requestIdleCallback' in window;// 回退到 setTimeout
const idleCallback = supportsIdleCallback ? requestIdleCallback : (callback) => setTimeout(() => callback({timeRemaining: () => 50, // 模拟50msdidTimeout: false}), 1);const cancelIdleCallback = supportsIdleCallback ?cancelIdleCallback :clearTimeout;// 使用兼容版本
const handle = idleCallback((deadline) => {// 你的代码
});// 需要时取消
// cancelIdleCallback(handle);

6. 注意事项

  1. 不要用于关键任务:空闲回调的执行时间不确定
  2. 避免修改DOM:可能引起重排重绘,影响性能
  3. 任务要可中断:确保能在timeRemaining()用尽时暂停
  4. 内存管理:及时取消不再需要的回调
  5. 超时设置谨慎:超时可能影响用户体验
// 不好的做法 - 可能阻塞用户交互
requestIdleCallback(() => {// 执行同步的繁重计算heavySynchronousCalculation(); // ❌
});// 好的做法 - 任务可分割
requestIdleCallback(function processChunk(deadline) {while (deadline.timeRemaining() > 0 && hasMoreWork) {processWorkUnit();}if (hasMoreWork) {requestIdleCallback(processChunk);}
});

requestIdleCallback 是优化网页性能的重要工具,特别适合处理那些重要但不紧急的后台任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/936745.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端开发调试实战指南,从浏览器到 WebView 的全链路问题排查思路

本文系统介绍前端开发调试的完整流程与工具组合,包括 Chrome DevTools、Charles、Postman、WebDebugX 等,结合实战案例总结桌面、框架、网络与 WebView 的调试前端开发看似写的是页面,实际做的是“排雷”。 代码写十…

基于EKF/UKF的非线性飞行器系统滤波实现

基于EKF/UKF的非线性飞行器系统滤波实现(CA/CV/Jerk/Sin模型)1. 系统模型定义 1.1 模型分类与状态方程1.2 观测模型2. EKF算法实现 2.1 核心步骤 % 初始化 x_est = [x0; y0; v0; ...]; % 初始状态 P_est = diag([10…

go-基于 Prometheus 的全方位食用手册 - fox

Go 指标监控实战:基于 Prometheus 的全方位食用手册 在微服务和分布式系统中,“看不见”的问题往往是最致命的——内存泄漏、接口响应延迟飙升、错误率突增,这些问题如果没有及时发现,很容易引发线上故障。而 指标…

实验任务2 - pp

task-1 源代码#include <stdio.h> #include <stdlib.h> #include <time.h> #define N 5 #define N1 80 #define N2 35 int main() {int cnt;int random_major, random_no; srand(time(NULL));// 以当…

插入公式总是有个框框

在word文档中,通过自定义样式,插入公式总是有一个虚线框 解决办法:样式中的【图文框】---【删除文本框】---【确定】---【确定】

picard标记DI/DS标签

picard标记DI/DS标签代码示例java -jar /mnt/zmds01/Product/bioinfo/gitlab/biobase/bin/picard.jar MarkDuplicates \ I="input.sort.bam" \ O="out_marked_dup.bam" \ M="out_dup_mertric…

2025年成都全日制辅导机构优选指南,全日制培训班/集训机构/集训班/全日制一对一培训/文化课集训机构,学习提升新选择

在当今这个知识快速更新、竞争日益激烈的时代,教育培训市场呈现出蓬勃发展的态势,人们对自我提升的渴望愈发强烈。无论是职场人士为了增强自身竞争力,还是成年人追求知识的充实与拓展,都在积极探寻更高效的学习途径…

2025 年灭老鼠公司最新推荐排行榜:欧盟认证技术与环保服务双优品牌权威甄选,含成都 / 四川专业机构口碑指南除老鼠/消灭老鼠/老鼠消杀公司推荐

鼠患已成为城市家居、商业场所及农业生产的重大隐患:家庭中老鼠啃噬设施、传播鼠疫等 30 余种疾病,商业场所因鼠患面临卫生合规风险,农业领域鼠害年均造成超百亿产量损失。然而当前市场乱象丛生:部分机构依赖高毒药…

uni-app x初探

一、概述 uni-app x,是下一代 uni-app,是一个跨平台应用开发引擎。 uni-app x 是一个庞大的工程,它包括uts语言、uvue渲染引擎、uni的组件和API、以及扩展机制。 uts是一门类ts的、跨平台的、新语言。 uts在Android…

第二次实验作业

1 #include<stdio.h>2 #include<stdlib.h>3 #include<time.h>4 5 #define N 56 #define N1 807 #define N2 358 9 int main(){ 10 int cnt; 11 int random_major, random_no; 12 13 …

深度SEO优化的方式有哪些,从技术层面来说

深度SEO优化涉及到一些技术层面的优化策略,以下是一些常见的方式: 1.网站结构优化:优化网站的结构,确保每个页面都可以被搜索引擎爬取和索引。使用合适的HTML标签和语义化的内容结构,使搜索引擎能够更好地理解页面…

2025 年南昌装修公司推荐南昌市宿然装饰工程有限公司,以专业与真诚雕琢理想空间南昌装修设计推荐指南!

在南昌,装修行业正处于蓬勃发展的阶段,市场上各类装修公司琳琅满目。消费者在选择时,往往期望找到一家既能提供创新设计,又能确保装修效果完美落地的公司。在这一背景下,南昌宿然设计机构以其独特的优势,在竞争激…

C# Avalonia 16- Animation- AnimateRadialGradient

C# Avalonia 16- Animation- AnimateRadialGradient用我们自己写的Player C# Avalonia 15- Animation- AnimationPlayerTest AnimateRadialGradient.axaml代码<Window xmlns="https://github.com/avaloniaui&q…

ControlNet——AI图像生成的“精准操控工具”

本文详细介绍了Stable Diffusion最强大的插件ControlNet的原理及典型应用,并介绍其安装及相关模型下载注意事项,最后还结合实例介绍了主要模型的使用方法。1 简介及安装 1.1 简介 ControlNet是由斯坦福大学研究者张吕…

2025 年国内模切加工源头厂家最新推荐排行榜:聚焦 0.1mm 精度与高产能标杆,为下游企业精选优质合作商电子辅料/硅胶/薄膜/胶黏/绝缘模切加工厂家推荐

当前模切加工行业在制造业产业链中地位关键,却面临厂家水平参差不齐的问题。部分厂家精度不足、废料率高、服务不稳定,难以满足下游汽车、医疗、电子等领域日益严苛的需求,让企业选合作商时倍感困扰。为帮助下游企业…

直播协议详解 RTMP、HLS、HTTP-FLV、WebRTC、RTSP 的区别

直播协议详解 RTMP、HLS、HTTP-FLV、WebRTC、RTSP 的区别直播协议详解 RTMP、HLS、HTTP-FLV、WebRTC、RTSP 的区别 本期我们详细讨论直播的相关协议,包括:HTTP-FLV、HLS、RTMP、Web-RTC、RTSP等等。 我们将会详细介绍…

2025 武汉实缴服务机构最新推荐排行榜:知识产权 / 注册资本代办优选清单,深度解析专业服务品质

新修订《公司法》明确要求企业注册资本五年内完成实缴,非货币出资合法化成为趋势,这既为企业发展划定合规红线,也让无形资产转化迎来机遇。武汉作为科创重镇,科技型企业密集,对知识产权实缴、政策适配等专业服务需…

华为开发者空间携手乐知行:轻松实现智能网联小车数据可视化系

本文分享自华为云社区《华为开发者空间携手乐知行:轻松实现智能网联小车数据可视化系》,作者:华为开发者空间小助手。 在AI重塑课堂、算力驱动教学创新的今天,让前沿技术从“概念”落地为“可感知的教学工具”,让…

card滑动效果

<template><view class="member-benefits"><!-- 卡片滑动容器 --><view class="card-slider" :style="{background: currentSliderGradient,transition: background 0.…

2025年成都一对一培训机构优选榜:成都一对一辅导/补习/培训/补习班/辅导机构推荐,成都美博教育脱颖而出

在当今快速发展的时代,人们对自我提升的渴望愈发强烈,教育培训市场也因此迎来了蓬勃发展的黄金时期。无论是想要提升职业技能以适应职场竞争,还是追求个人兴趣爱好的培养,又或是为了满足知识更新的需求,越来越多的…