为什么递归调用requestAnimationFrame不会触发栈溢出错误?
问题1:为什么递归调用requestAnimationFrame不会栈溢出?
你的猜测完全正确,核心原因是requestAnimationFrame属于异步调度API,不会在当前调用栈同步执行传入的回调,不存在调用栈深度累加的情况。
我们可以对比同步递归和这种异步"递归"的执行差异:
- 普通同步递归的执行逻辑是:调用
foo()时会立刻在当前调用栈压入新的foo执行上下文,栈深度会随着递归次数持续增加,超过浏览器栈容量限制就会触发爆栈错误。 - 你写的
requestAnimationFrame版本逻辑是:- 首次调用
foo(),压入调用栈 - 执行
requestAnimationFrame(foo):只是向浏览器提交了一个「下次重绘前执行foo」的调度请求,该方法立刻返回,不会当场执行foo - 执行
console.log("foo"),执行完成后foo出栈,当前调用栈完全清空 - 浏览器到下一次重绘时机时,才会把之前提交的foo回调拿出来,压入空的调用栈执行,重复上述流程
- 首次调用
全程每次执行foo时调用栈的深度都是从0开始累加,永远不会超过单次执行的栈深度,自然不会触发栈溢出。你类比的setTimeout异步调用逻辑和requestAnimationFrame的运行原理完全一致,唯一区别只是两者所属的调度队列优先级不同:setTimeout回调属于普通宏任务队列,requestAnimationFrame回调在浏览器渲染流水线的重绘阶段执行,优先级更高,但本质都是异步队列调度,不会同步执行回调。
问题2:持续提交异步回调会不会触发错误?
只要你单次异步回调内部的执行逻辑没有同步的深层递归,单次执行的栈深度控制在合理范围内,就不会触发栈溢出错误。
不过要注意两个额外限制:
- 如果单次回调的执行耗时过长(超过单帧预算16ms),会导致页面掉帧、交互响应卡顿
- 页面被切到后台隐藏时,大部分浏览器会暂停
requestAnimationFrame的触发,避免不必要的资源消耗
内容的提问来源于stack exchange,提问作者hdw3
相关产品推荐
相关产品推荐

