You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

含while循环的React useEffect执行时序疑问:为何2在3、4之后打印?

问题解答:useEffect回调打印顺序异常的原因

这个问题的核心在于React的调度机制与浏览器事件循环的交互,以及主线程阻塞对任务优先级的影响:

1. 关键概念铺垫

  • 同步代码:立即执行,阻塞主线程直到执行完毕。
  • 微任务:Promise回调、MutationObserver等,同步代码执行完后会被优先批量处理。
  • 宏任务:setTimeout、setInterval、I/O操作等,微任务处理完毕后才会开始执行。
  • React调度器(Scheduler):React内置的异步任务调度工具,会根据主线程繁忙程度动态调整任务优先级。

2. 带while循环的执行流程

// 同步代码阶段
console.log(1); // 打印1
// 阻塞主线程50ms,浏览器无法处理任何其他任务
const start = Date.now();
while (Date.now() - start < 50) {
  window.timestamp = Date.now();
}

// React组件渲染完成进入commit阶段,将useEffect回调调度为低优先级异步任务
useEffect(() => console.log(2), [state]);

// 向微任务队列添加任务
Promise.resolve().then(() => console.log(3));
// 向宏任务队列添加任务
setTimeout(() => console.log(4), 0);

同步代码执行完毕后,事件循环按如下顺序处理任务:

  1. 优先清空微任务队列:执行Promise回调,打印3。
  2. 处理宏任务队列:执行setTimeout回调,打印4。
  3. 主线程彻底空闲后,React调度器的低优先级任务(useEffect回调)才会执行,打印2。

3. 移除while循环的执行流程

去掉while循环后,同步代码瞬间执行完毕,主线程处于空闲状态:

  1. React调度器会立即执行useEffect回调(此时任务优先级足够高),打印2。
  2. 清空微任务队列:执行Promise回调,打印3。
  3. 处理宏任务队列:执行setTimeout回调,打印4。

总结

  • 主线程被长时间阻塞(while循环)时,React会将useEffect回调降级为低优先级任务,推迟到微任务、宏任务之后执行。
  • 主线程空闲时,React会优先调度useEffect回调,使其先于微任务、宏任务执行。

内容的提问来源于stack exchange,提问作者Janice Zhong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 23:30:24