🤯Incredible phenomenon: strange execution order before and after setState #34039
-
const [data, setDate] = useState(0);
function handleEvent() {
Promise.resolve().then(() => {
console.log(4)
})
console.log(1)
setData(() => {
console.log(2)
})
console.log(3);
} So, if the output order of the code above is 1, 2, 3, 4, that's normal and expected. In fact, most of the time, the output is indeed 1, 2, 3, 4. However, during development, I occasionally observed the output order as 1, 3, 2, 4, where 1, 3, and 2 were printed almost immediately one after another, followed by 4 a few milliseconds later. This completely challenged my understanding of JavaScript's execution order. Aren't microtasks supposed to be the highest-priority mechanism executed right after a macrotask? What technique is React using here? BTW, My application runs within the CEF framework, using Chrome version 124 (Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 AIAgent/3.0.3.7161). |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 3 replies
-
Beta Was this translation helpful? Give feedback.
-
The behavior you're observing is indeed interesting, but I need to clarify a few misconceptions about what's actually happening here. The normal and expected order is 1, 2, 3, 4, and here's why:
The occasional reordering to The anomalous behavior is likely caused by:
React's batching affects when re-renders happen, not when updater functions execute. The updater function itself runs synchronously to calculate the new state value. Microtasks (like |
Beta Was this translation helpful? Give feedback.
-
我觉得应该是 React 的useState 为了优化是异步批处理的。
也就是说,console.log(2) 不一定在你 setData 之后马上发生 |
Beta Was this translation helpful? Give feedback.
I think I understand the reason now—the callback of setState isn't always invoked "synchronously"(execute immediately).
This is exactly what happens in the case of 132. When execution finishes inside the effect (at this point, 1 and 3 are printed, and the callback is added to the queue, i.e.,
concurrentQueues
), React schedules the queue to be processed, and then 2 gets printed.However, all of this occurs within a single macrotask, which is why they appear to execute almost simultaneously.