batchedUpdates与事务
目前为止一些准备工作已经就绪,接下来我们将进入渲染阶段的处理。
文件依然是 src/renderers/dom/client/ReactMount.js,根据前一小节,我们可以知道根节点的DOMComponent 对象或者 ReactCompositeComponent 对象创建成功,接着会调用 ReactUpdates.batchedUpdates ,这是一个批量更新的方法,我们可以在源文件中进一步阅读。
batchingStrategy.batchedUpdates(callback, a, b, c, d, e);
源文件中只不过是继续调用了一下另外一个 batchedUpdates 方法,这个方法你可以在 src/renderers/shared/reconciler/ReactDefaultBatchingStrategy.js 中阅读,整个代码量并不多,一个 isBatchingUpdates 布尔值变量以及一个 batchedUpdates 方法:
var ReactDefaultBatchingStrategy = {
isBatchingUpdates: false,
batchedUpdates: function(callback, a, b, c, d, e) {
var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;
ReactDefaultBatchingStrategy.isBatchingUpdates = true;
if (alreadyBatchingUpdates) {
callback(a, b, c, d, e);
} else {
transaction.perform(callback, null, a, b, c, d, e);
}
},
};
很明显初始化时的 alreadyBatchingUpdates 是一个 false ,于是我们进入了 transaction.perform,而这个callback则传入了定义在 ReactMount.js 中的 batchedMountComponentIntoNode 函数,恰好这个函数中也定义了一个 transaction.perform 传入的是 mountComponentIntoNode 函数,如果你从这跟进去之后你会发现真实的DOM节点是从 ReactReconciler.mountComponent 中return而来,它存储在node节点中,巧妙的是最后添加到浏览器中使用的是insertBefore,这说明React不是将DOM做为字符串处理的而是真实的 document.createElement 创建的DOM对象。
Transaction
一路下来我们发现了很多 transaction.perform 的调用,那么它又是什么呢?

源码中的这张图很形象的说明了 Transaction 的作用,整个过程从perform开始会调用 initialize 方法,中间也许会处理很多其它方法,最后到调用close方法结束。对于 React 来说 Transaction 到底有什么作用呢?其实从初始化开始如何转化为真实的DOM元素这一个步骤中间,我们就能看到有非常多的 transaction.perform 的调用。
事务一般来说在数据库操作时非常常见,这个设计模式目标是在于并发访问多个构件之间共享的数据,它只是一个执行单元。那如果在 React 中,我们该如何理解这个设计呢?
实际上React是封装了一个Mixin来处理Transaction的,事务给需要执行的函数包装了两个wrapper,每个wrapper都有 initialize 和 close 方法。当一个事务需要 perform 的时候,都会先调用相应的 initialize 方法,同样的在事务结束的时候会调用 close 方法,这样才会构成了一个完整的事务。
通过调用栈,我们可以很清楚的知道(这里不涉及setState,因为这是初始化。)React 将渲染的处理包装成了事务,通过这个事务来处理的比如计算props,生成DOM节点等。