异步 API,比如 setTimeout , setInterval , requestIdleCallback 和requestAnimationFrame 还有 Promise ,这几个的区别?

📅 2026/7/13 16:46:57
异步 API,比如 setTimeout , setInterval , requestIdleCallback 和requestAnimationFrame 还有 Promise ,这几个的区别?
面试先给结论这几个都和“异步调度”有关但它们不属于同一类机制区别主要在进入哪种任务队列执行时机是否和浏览器渲染相关是否会重复执行适合什么场景可以先用一句话概括setTimeout/setInterval属于宏任务调度Promise.then属于微任务requestAnimationFrame是浏览器下一帧渲染前执行requestIdleCallback是浏览器空闲时执行。一、先分类API类型执行时机是否重复常见用途setTimeout宏任务指定时间后尽快执行否延迟执行、一次性任务setInterval宏任务每隔一段时间重复执行是轮询、周期任务Promise.then微任务当前同步代码执行完后立即执行在下一个宏任务前否异步链式调用、状态变更后立即处理requestAnimationFrame渲染调度浏览器下一次重绘前执行否需手动递归动画、DOM 视觉更新requestIdleCallback空闲调度浏览器主线程空闲时执行否需手动递归低优先级任务、非关键计算二、一个个说区别1.setTimeout特点指定一个最小延迟时间时间到了以后不是“立刻执行”而是进入宏任务队列等待执行只执行一次示例setTimeout(() { console.log(timeout) }, 1000)注意点即使写setTimeout(fn, 0)也不是马上执行只是表示当前同步代码和当前轮事件循环任务处理完后尽快执行适用场景延迟执行一段逻辑让任务晚一点执行模拟异步节流/防抖内部实现2.setInterval特点每隔固定时间把回调放入宏任务队列会重复执行直到手动清除const timer setInterval(() { console.log(interval) }, 1000) clearInterval(timer)问题如果回调执行时间太长可能出现间隔不准任务堆积比如设置每 1 秒执行一次但函数本身执行了 2 秒那么就可能紊乱。更推荐的替代方案很多场景下比起setInterval更推荐function loop() { setTimeout(() { console.log(do something) loop() }, 1000) } loop()因为这样可以保证“本次执行完再开始下一次计时”。适用场景简单轮询周期性检查定时刷新3.Promise这里更准确地说是Promise的回调如then / catch / finally会进入微任务队列特点微任务执行时机比宏任务更早当前同步代码执行完- 先清空微任务队列- 再执行下一个宏任务示例console.log(1) setTimeout(() { console.log(2) }, 0) Promise.resolve().then(() { console.log(3) }) console.log(4)输出顺序1 4 3 2为什么因为1、4是同步Promise.then是微任务setTimeout是宏任务所以微任务先执行。适用场景异步结果处理链式调用需要“尽快但异步”执行的逻辑4.requestAnimationFrame这是和浏览器渲染帧相关的 API。特点回调会在下一次浏览器重绘前执行更适合做动画一般一帧约 16.6ms60fps不会自动重复需要自己递归调用示例function animate() { console.log(before paint) requestAnimationFrame(animate) } requestAnimationFrame(animate)为什么适合动画因为它是跟着浏览器刷新节奏走的浏览器准备绘制下一帧时调用你可以避免不必要的重绘比setInterval更平滑适用场景动画平滑滚动拖拽更新位置与视觉变化强相关的 DOM 操作和setTimeout做动画的区别setTimeout不跟浏览器帧同步容易掉帧页面隐藏时也可能继续触发requestAnimationFrame与浏览器重绘同步更节能、更流畅页面隐藏时通常会暂停或降频5.requestIdleCallback这是空闲回调。特点只有当浏览器主线程空闲时才执行属于低优先级任务调度不适合做实时、关键逻辑兼容性不如前几个 API好些项目会做降级处理示例requestIdleCallback((deadline) { while (deadline.timeRemaining() 0) { console.log(do idle work) } })参数deadline它会告诉你当前空闲时间还剩多少deadline.timeRemaining()deadline.didTimeout这样你可以把大任务拆开做。适用场景非紧急埋点处理大数据分片计算预加载后台缓存整理不影响首屏渲染的低优先级任务不适合动画用户交互后的立即反馈高优先级更新三、它们的核心区别执行优先级和时机这个是面试官最想听的。1. 同步 微任务 宏任务先记住这个顺序同步代码先执行当前调用栈清空后执行微任务微任务清空后再执行宏任务所以Promise.then比setTimeout更早执行setTimeout/setInterval是下一轮事件循环的宏任务2.requestAnimationFrame跟“渲染”绑定它不是单纯按时间排队而是浏览器准备绘制下一帧时调用所以它和动画更匹配。3.requestIdleCallback跟“空闲”绑定它也不是严格定时而是浏览器有空才执行所以适合低优先级任务。四、简单理解成“谁更快”这题经常有人答错不能简单说谁绝对更快。更准确的说法是Promise.then在当前任务结束后优先执行通常比setTimeout更早setTimeout时间到了进入宏任务队列不保证马上执行requestAnimationFrame下一帧绘制前执行requestIdleCallback空闲时执行不保证很快setInterval按间隔重复调度但也会受主线程阻塞影响五、典型面试代码题例子 1console.log(start) setTimeout(() { console.log(setTimeout) }, 0) Promise.resolve().then(() { console.log(promise) }) console.log(end)输出start end promise setTimeout原因同步先执行start、end微任务promise宏任务setTimeout例子 2requestAnimationFrame(() { console.log(raf) }) setTimeout(() { console.log(timeout) }, 0)这个不一定在所有场景下都能机械地说谁先谁后但面试里可以这么答requestAnimationFrame是在下一次重绘前执行setTimeout是宏任务。具体顺序会受到浏览器调度、当前渲染时机影响但从使用目的上requestAnimationFrame是为视觉更新设计的不建议和setTimeout用来做同类事情比较先后。这样更严谨。六、实际开发中怎么选1. 想延迟执行一次用setTimeout2. 想周期执行简单场景setInterval更稳一些setTimeout 递归3. 想在本轮同步代码之后尽快执行用Promise.then或者框架里的 nextTick 本质上很多时候也是借助微任务。4. 想做动画或 DOM 位移用requestAnimationFrame5. 想把不重要的任务延后避免影响交互用requestIdleCallback七、面试标准回答模板你可以直接背这段这几个异步 API 的主要区别在于它们的调度机制和执行时机不同。setTimeout和setInterval属于宏任务前者是延迟一次执行后者是周期性执行Promise.then属于微任务会在当前同步代码执行结束后、下一个宏任务之前执行所以通常比setTimeout更早requestAnimationFrame是在浏览器下一次重绘前执行适合做动画和视觉更新requestIdleCallback是在浏览器空闲时执行适合做低优先级、不影响用户交互的任务。所以实际开发中如果是异步结果处理我会用 Promise如果是动画我会优先用 requestAnimationFrame如果是低优先级后台任务会考虑 requestIdleCallback。八、再补一个“事件循环”层面的回答如果面试官继续追问你可以再说从事件循环角度看Promise.then进入微任务队列setTimeout和setInterval进入宏任务队列每次宏任务执行结束后JS 引擎会先清空微任务队列再决定是否进行渲染。requestAnimationFrame是浏览器在渲染前调用requestIdleCallback是浏览器在空闲阶段调用所以它们更偏向浏览器调度而不只是普通任务队列。这段比较加分。九、30 秒短答版setTimeout和setInterval是宏任务分别用于延迟一次执行和定时重复执行Promise.then是微任务执行优先级比宏任务高requestAnimationFrame是浏览器下一帧渲染前执行适合动画requestIdleCallback是浏览器空闲时执行适合低优先级任务。所以它们的核心区别就是任务队列不同、执行时机不同、适用场景不同。十、一句话总结Promise看“任务优先级”setTimeout/setInterval看“时间”requestAnimationFrame看“渲染帧”requestIdleCallback看“空闲时间”。