接上文,
React流程图:
https://bogdan-lyashenko.gith…
‘脏’组件
从流程图里能看出,React会遍历dirtyComponents数组,并在事务中调用ReactUpdates.runBatchedUpdates。这个事务是个新事务。那么为什么要这么设计呢?
此事务的类型为ReactUpdatesFlushTransaction,在此之前我们已经提到过,我们去看下其相应的包装器以方便我们理解这个事务具体完成什么任务。代码里有如下注释:
ReactUpdatesFlushTransaction包装器会清空dirtyComponents数组,并且执行所有已经压入队列里的更新操作,这些操作一般都是由过程后的处理方法压入的(比如,commponentDidUpdate方法)(ReactUpdatesFlushTransaction’s wrappers will clear the dirtyComponents array and perform any updates enqueued by mount-ready handlers (i.e., componentDidUpdate))
我们也验证下是否代码真的这样运转。该事务有两个包装器,NEST_UPDATES和UPDATE_QUEUEING。在事务的初始化阶段,我们会先把dirtyComponentsLength存储起来,然后在关闭阶段,React进行组件比较。在更新过程中,很可能dirtyComponents组件都发生里改变,所以,需要不止一次的运行flushBatchedUpdates方法。代码比较直白,没有什么黑魔法。
但是,这里其实有个地方需要注意下,ReactUpdatesFlushTransaction覆盖了Transaction.perform方法,之所以这么做,是因为,执行更新时需要调用ReactReconcileTransacation里的行为(这个事务在挂载过程中也使用到了,目的是为了确保应用状态安全)。所以,在ReactUpdatesFlushTransaction.perform方法的执行过程中,ReactReconcileTransaction方法会被调用到,所以,就是把事务方法在包了一次。
整个技术流程大概如此:
[NESTED_UPDATES, UPDATE_QUEUEING].initialize()
[SELECTION_RESTORATION, EVENT_SUPPRESSION, ON_DOM_READY_QUEUEING].initialize()
method -> ReactUpdates.runBatchedUpdates
[SELECTION_RESTORATION, EVENT_SUPPRESSION, ON_DOM_READY_QUEUEING].close()
[NESTED_UPDATES, UPDATE_QUEUEING].close()
在此文的最后,我们会回到事务方法,在确认下事务是如何帮助方法完成的,但在此之前,我们先确认下ReactUpdates.runBatchedUpdates的实现。(srcrendererssharedstackreconcilerReactUpdates.js#125)
在执行之前的第一步,就是把dirtyComponets进行排序,如何排序呢?基于mount order这个字段进行排序(一个整数值,在组件实例化时被设置进组件),这个字段代表父组件(它们也最先挂载)先更新,子组件接下去更新,以此类推。下一步,React会对updateBatchNumber加1操作,这个字段类似于当前处理DOM的ID,看下代码里的注释,看下代码里的注释:
在更新过程中加入队列的更新必须在批量操作执行完后再执行。否则,假设dirtyComponents为有组件A,B,其中A的子组件为B,B有子组件C,如果C有更新,则B将再次被压入队列,导致B被更新两次。对于这种情况,我们只能通过检查批量更新的计数器来跳过这次更新。(‘Any updates enqueued while reconciling must be performed after this entire batch. Otherwise, if dirtyComponents is [A, B] where A has children B and C, B could update twice in a single batch if C’s render enqueues an update to B (since B would have already updated, we should skip it, and the only way we can know to do so is by checking the batch counter).’)
这个设计避免了同一个组件的重复更新。
最后,我们遍历完整个dirtyComponents队列,然后把每个组件传递给了ReactReconciler.performUpdateIfNecessary,这个方法会在ReactCompisteCompoent里被调用,所以,最终我们又回到了ReactCompsiteComponet里的updateComponet方法。现在,我们可以更深入的研究下这个方法。
(未完待续)