当前位置: 首页 > news >正文

RequestldleCallback

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.hskmm.com/?act=detail&tid=30812

相关文章:

  • 前端开发调试实战指南,从浏览器到 WebView 的全链路问题排查思路
  • 基于EKF/UKF的非线性飞行器系统滤波实现
  • go-基于 Prometheus 的全方位食用手册 - fox
  • 实验任务2 - pp
  • 插入公式总是有个框框
  • picard标记DI/DS标签
  • 2025年成都全日制辅导机构优选指南,全日制培训班/集训机构/集训班/全日制一对一培训/文化课集训机构,学习提升新选择
  • 2025 年灭老鼠公司最新推荐排行榜:欧盟认证技术与环保服务双优品牌权威甄选,含成都 / 四川专业机构口碑指南除老鼠/消灭老鼠/老鼠消杀公司推荐
  • uni-app x初探
  • 深度SEO优化的方式有哪些,从技术层面来说
  • 2025 年南昌装修公司推荐南昌市宿然装饰工程有限公司,以专业与真诚雕琢理想空间南昌装修设计推荐指南!
  • C# Avalonia 16- Animation- AnimateRadialGradient
  • ControlNet——AI图像生成的“精准操控工具”
  • 2025 年国内模切加工源头厂家最新推荐排行榜:聚焦 0.1mm 精度与高产能标杆,为下游企业精选优质合作商电子辅料/硅胶/薄膜/胶黏/绝缘模切加工厂家推荐
  • 2025 武汉实缴服务机构最新推荐排行榜:知识产权 / 注册资本代办优选清单,深度解析专业服务品质
  • 华为开发者空间携手乐知行:轻松实现智能网联小车数据可视化系
  • card滑动效果
  • 学习日报
  • 2025年成都一对一培训机构优选榜:成都一对一辅导/补习/培训/补习班/辅导机构推荐,成都美博教育脱颖而出
  • 打印机共享修复,打印机无法共享,打印机修复工具下载及安装教程
  • web中静态资源加载失败的降级处理
  • 2025年保温隔热挤塑泡沫板推荐哪个厂家好?xps挤塑板/石墨聚苯板公司推荐
  • 实用指南:消息队列 MQ
  • 基于 Docker 部署 Alpine Linux:从入门到实践
  • 行列式按一行或列展开
  • 2025 年最新推荐高性价比实木家具厂家排行榜:涵盖实木床餐边柜/餐桌斗柜/书柜/梳妆台/床头柜/餐椅沙发/休闲椅优质厂家精选
  • 多智能体微服务实战(3/4):Aspire 打造本地 K8s 开发环境
  • 2025 年水下打捞公司服务推荐榜:水下打捞手机/水下打捞黄金/水下打捞戒指/水下打捞沉船/水下打捞转头,聚焦专业与高效,助力解决各类水下应急需求
  • SAP 中物料视图必填字段(用下程序定期校验)
  • 一文读懂Optimism,Arbitrum,ZK Rollups 共识算法