requestanimationframe(raf)不是宏任务或微任务,而是在每次重绘前由浏览器主动调度的同步回调,执行时机在微任务之后、渲染之前,与屏幕刷新率同步。

requestAnimationFrame(rAF)是浏览器提供的专门用于动画的 API,它和 JavaScript 事件循环紧密协作,但**并不属于事件循环的标准阶段(宏任务/微任务)**,而是由浏览器在每次重绘前主动调度的特殊回调。
requestAnimationFrame 的执行时机
rAF 回调被注册后,浏览器会将其安排在**下一次屏幕重绘之前**执行,通常与显示器刷新率同步(如 60Hz 下约每 16.7ms 一次)。这个时机由浏览器控制,不是开发者通过队列插入的,因此:
- rAF 不进入宏任务队列(setTimeout、setInterval、I/O 等),也不进微任务队列(Promise.then、queueMicrotask)
- 它在渲染流程中“插队”:浏览器完成当前 JS 执行 → 执行所有已注册的 rAF 回调 → 进行样式计算、布局、绘制、合成 → 显示帧
- 即使主线程正忙,rAF 也不会被丢弃,但可能被延迟到下一个帧(除非 tab 失去焦点,此时多数浏览器会暂停 rAF)
与事件循环各阶段的相对顺序
在一个典型的帧周期中,执行顺序大致如下(简化版):
- 执行当前宏任务(如 click 回调、setTimeout 回调)
- 执行本轮所有微任务(Promise.then、MutationObserver 等)
- 检查是否需要 rAF:若有待执行的 rAF 回调,**立即同步执行它们**(注意:这是关键——rAF 回调在此时运行,且是同步的)
- 进行渲染(样式、布局、绘制、合成)
也就是说,rAF 回调的执行发生在微任务之后、渲染之前,且是浏览器主动触发的“渲染前钩子”,不是事件循环“轮询”出来的。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
实际配合中的常见模式
利用 rAF 和事件循环特性,可以写出更流畅、可控的动画逻辑:
- 避免在 rAF 中做耗时计算:rAF 回调必须快(一般 ≤ 16ms),否则会挤占渲染时间,导致掉帧。复杂计算可拆分、用 Web Worker 或 requestIdleCallback 卸载
- 状态更新与 rAF 配合:比如用户连续触发 scroll,用 debounce + rAF 可确保只在下一帧更新 UI,而不是每滚一下就重排重绘
- 链式动画控制:在 rAF 回调末尾再次调用 rAF,形成自然帧循环;若中间插入了 Promise.then,它会在当前帧的 rAF 之后、下帧 rAF 之前执行,可用于“帧间异步协调”
一个小例子帮你理清时序
以下代码执行后,console 输出顺序是:
click → promise → raf → render → promise2 → raf2 → render2(假设两次点击间隔足够长,且无其他干扰)
button.addEventListener('click', () => {
console.log('click');
Promise.resolve().then(() => console.log('promise'));
requestAnimationFrame(() => console.log('raf'));
});
// 在 raf 回调里再注册一个
requestAnimationFrame(() => {
console.log('raf');
Promise.resolve().then(() => console.log('promise2'));
requestAnimationFrame(() => console.log('raf2'));
});
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










