关键是要将长任务拆分为≤16ms的微任务或宏任务,利用事件循环调度点(如requestidlecallback、promise.then、raf)在渲染间隙执行,确保每帧≤16.67ms以维持60fps流畅体验。

要让页面保持每秒 60 帧(即每帧 ≤ 16.67ms),关键不是“避免阻塞”,而是**主动把长任务拆成多个不超过 16ms 的微任务或宏任务**,让浏览器有空隙完成渲染、样式计算、布局和绘制。JavaScript 是单线程的,主线程被 JS 占满时,渲染就卡住——事件循环正是调度 JS 执行与渲染时机的机制。
理解帧预算与事件循环协作关系
浏览器每 16.67ms 尝试一次完整渲染周期(RAF → 样式 → 布局 → 绘制 → 合成)。但这个周期只会在**JS 调用栈为空且没有待处理的微任务/宏任务时**才真正执行。也就是说:哪怕你只写了一个耗时 20ms 的 for 循环,它会独占主线程,导致这一帧直接丢弃,用户看到卡顿。
事件循环本身不“保证帧率”,但它提供了可插入的调度点(如 setTimeout、Promise.then、queueMicrotask、requestIdleCallback),让你把大任务切开,在渲染间隙中逐步执行。
用 requestIdleCallback 拆分非紧急任务
这是最贴合“帧预算”理念的 API:它在浏览器空闲时段(即渲染完成后、下帧开始前)回调,自动避开关键渲染路径,并提供剩余空闲时间(deadline.timeRemaining()),方便你判断还能干多少事。
- 适合:数据预处理、日志上报、非实时 DOM 更新、复杂状态计算
- 注意:不是所有浏览器都支持(IE 不支持,需 polyfill),且空闲时间可能极短(甚至为 0),必须检查
deadline.didTimeout - 示例:
function processBigList(list, index = 0) { const chunkSize = 100; const endIndex = Math.min(index + chunkSize, list.length); for (let i = index; i { if (deadline.timeRemaining() > 1) { processBigList(list, endIndex); } else { setTimeout(() => processBigList(list, endIndex), 0); } }); } }
用 Promise / queueMicrotask 实现细粒度微任务切分
微任务在每次宏任务结束后立即执行,但**不会打断当前帧的渲染流程**。如果一个任务能拆成几十次微任务,每次只做一点点,就能在不明显卡顿的前提下推进工作。
- 适合:需要较快响应、但又不能阻塞渲染的逻辑,如状态同步、轻量级计算链
- 注意:过度使用微任务可能导致渲染被延迟(因为微任务队列清空完才进入渲染),所以单次微任务执行时间仍建议控制在 1–3ms 内
- 示例(安全拆分 10000 次计算):
async function splitCalculation(data) { for (let i = 0; i {}); } }
配合 requestAnimationFrame 精确对齐渲染节奏
如果你的任务和视觉更新强相关(比如动画、滚动联动、Canvas 绘制),应该用 requestAnimationFrame(RAF)驱动,而不是定时器。RAF 回调会在下一帧开始前执行,天然对齐浏览器刷新节奏。
- 适合:动画帧更新、滚动视差、Canvas 动画、基于 scroll 的懒加载
- 技巧:可在 RAF 中先读取 DOM(如
getBoundingClientRect),再用setTimeout或微任务延后写入(避免强制同步布局),实现“读写分离” - 示例(平滑滚动处理):
function handleScroll() { // 读取:安全,无副作用 const scrollTop = window.scrollY; // 写入:延后到微任务,避免 layout thrashing queueMicrotask(() => { updateUIBasedOn(scrollTop); }); } window.addEventListener('scroll', () => { requestAnimationFrame(handleScroll); });
不复杂但容易忽略:帧率稳定不是靠“快”,而是靠“匀”。把 100ms 的活,切成 6 个 16ms 的块,比压成 1 个 90ms 的块更流畅。事件循环是你的节拍器,用好 requestIdleCallback、requestAnimationFrame 和微任务,就是给浏览器留出呼吸空间。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











