React 批处理机制
React 批处理机制
我们开发过程中发现,调用 setState,然后获取 state 时候,发现不是最新的值,这是为什么呢?这就和 React 批处理机制有关系。
一次性调用好几次 setState,肯定不会调用一次组件就更新渲染一次,这样太消耗性能了。
react 做法,每次调用都记录下来,然后合并得到最新的值,最后才执行更新。
一般来说生命周期、react 事件里面都会命中批处理机制。
批处理的流程如下:
setState 本身并不是异步的,只不过批处理的机制,给人一种异步的假象。
分析一下整体流程:
● 当我们触发更新时候 setState
● 页面不会立即更新,而是把 state 存入 pendingState 队列中,要更新的组件存入 dirtyComponent 队列中。
● 是否开始更新,有个开关控制的 isBatchingUpdate,它是全局变量,如果为 false 才会进行更新。
什么时候为 false?
● 变量初始化时候(页面第一次渲染的时候)。
● 上一次更新执行完毕的时候。
● 为了 false 了,就把 dirtyComponent 中组件和 pendingState 的 state 进行更新,此时又把 isBatchingUpdate 设置为 true,这样就可以确保组件不会被重新渲染多次。
所以说下面的代码不会打印出最新的值,因为 state 都被缓存到 pendingState 里面了,要等批处理机制完成后才会统一更新的。
1 |
|
为什么定时器里面和原生事件里面可以获取最新的值?
结论:异步代码,事件循环导致。
上面提到了有个全局变量 isBatchingUpdate,默认是 false,更新开始设置为 true,更新结束为 false。
1 |
|
分析一下上面的代码,为什么可以获取最新的值。
- 一开始 isBatchingUpdate 为 false。
- 点击按钮执行了定时代码,由于 setTimeout 是异步代码,回调函数不会立即执行,要等同步代码执行完毕,进行事件循环的时候才会执行。
- 代码走完了,没有更新操作,isBatchingUpdate 也就不会设置为 true。
- 等到事件循环,执行定时器的回调函数,但是此时 isBatchingUpdate 是 false,就直接对 pendingState 和 dirtyComponent 进行更新,所以下面的 log 可以获取到最新的数据。(从上面流程图可以看出)