事务机制

事务机制是React中非常重要的机制,这里的事务区别于数据库中的事务,它是一个借用的概念,与其说是事务,更像是拦截器(Interceptor)。React中的事务进行了两层“抽象“,一层是抽象的事务接口定义,其代码都在src/utils/Transaction.js中,另外一层是基于抽象的Transaction定义了在React框架中通用的事务流程ReactReconcileTransaction,更确切的说,Transaction是接口,而ReactReconcileTransaction则是其具体实现。

Transaction

关于事务机制的设计,React源代码中给出了一份草图描述其工作原理,如下所示

 /*                       wrappers (injected at creation time)
 *                                      +        +
 *                                      |        |
 *                    +-----------------|--------|--------------+
 *                    |                 v        |              |
 *                    |      +---------------+   |              |
 *                    |   +--|    wrapper1   |---|----+         |
 *                    |   |  +---------------+   v    |         |
 *                    |   |          +-------------+  |         |
 *                    |   |     +----|   wrapper2  |--------+   |
 *                    |   |     |    +-------------+  |     |   |
 *                    |   |     |                     |     |   |
 *                    |   v     v                     v     v   | wrapper
 *                    | +---+ +---+   +---------+   +---+ +---+ | invariants
 * perform(anyMethod) | |   | |   |   |         |   |   | |   | | maintained
 * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | +---+ +---+   +---------+   +---+ +---+ |
 *                    |  initialize                    close    |
 *                    +-----------------------------------------+
 */

这张图形象详细地描述了整个抽象事务的工作过程。简言之,就是在执行perform(或者其他方法)前,执行若干个wrapper函数,以保证perform执行过程中,不会出现数据错乱等问题。

事务执行分为3个阶段,初始化阶段,执行阶段和关闭阶段。在初始化阶段,每一个wrapper的initialize方法都会被调用并执行,为了方便close阶段的数据共享,initialize阶段的执行结果会被保存,并且在相应的close方法执行时会作为参数传入。 具体到代码层面,transaction的mixin中定义了下面几个重要方法,除了getTransactionWrapper没有具体实现。

getTransactionWrappers

这是一个抽象函数,Transaction类中没有其对应的方法体,继承Transaction的类,必须给出该方法的具体实现,ReactReconcileTransaction就实现了这个方法。

peform

事务执行的核心方法,它接受7个参数,第一个参数是要在事务中执行的method函数,第二个参数时执行method函数的scope,后面的参数是执行method函数的传参。

React限制了method能够接受的参数数量不能超过5个**。**5个参数的限制在缓冲池机制中也有体现,或许是facebook的程序员认为,一个函数的参数以不超过5个为宜吧。

在method执行之前,React会通过调用initializeAll方法执行所有wrapper的initialize方法;method在try-catch语句块中执行;closeAll方法则会在finally中被调用。

跨阶段数据传递

有时侯事务初始化阶段的结果会需要被传递到close阶段使用,例如在事件事务处理时,某些全局事件的监听状态,需要在initialize时被关闭,而等到close阶段时,恢复成原来的状态(打开或关闭)。为了能够满足这样的数据传递需求,React会将每个wrapper函数的initialize执行结果保存到wrapperIniData中,等到执行close方法时,再把数据传递过去,其关键源码节选如下:

保存initialize执行结果

var transactionWrappers = this.transactionWrappers;
    var wrapperInitTimes = this.timingMetrics.wrapperInitTimes;
    var err = null;
    for (var i = 0; i < transactionWrappers.length; i++) {
      var initStart = Date.now();
      var wrapper = transactionWrappers[i];
      try {
        this.wrapperInitData[i] =
          wrapper.initialize ? wrapper.initialize.call(this) : null;
      } catch (initErr) {
        err = err || initErr;  // Remember the first error.
        this.wrapperInitData[i] = Transaction.OBSERVED_ERROR;
      } finally {
        var curInitTime = wrapperInitTimes[i];
        var initEnd = Date.now();
        wrapperInitTimes[i] = (curInitTime || 0) + (initEnd - initStart);
      }
    }
    if (err) {
      throw err;
    }

传递数据

 for (var i = 0; i < transactionWrappers.length; i++) {
      var wrapper = transactionWrappers[i];
      var closeStart = Date.now();
      var initData = this.wrapperInitData[i];
      try {
        if (initData !== Transaction.OBSERVED_ERROR) {
          wrapper.close && wrapper.close.call(this, initData);
        }
      } catch (closeErr) {
        err = err || closeErr;  // Remember the first error.
      } finally {
        var closeEnd = Date.now();
        var curCloseTime = wrapperCloseTimes[i];
        wrapperCloseTimes[i] = (curCloseTime || 0) + (closeEnd - closeStart);
      }
    }

ReactReconcileTransaction

Transaction中定义了抽象的事务处理过程,而具体到React的事务处理过程,则是通过ReactReconcileTransaction来完成的。

ReactReconcileTransaction中除了mix了抽象Transaction的mixin,还额外定义了自己的mixin,其中包含3个主要方法。

getTransactionWrapper

这是实现抽象事务必须实现的一个方法,该方法返回事务处理的所有wrapper函数。React事务处理的所有Wrapper都定义在TRANSACTION_WRAPPERS中(src/core/ReactReconcileTransaction.js),主要包括3个wrapper,分别是

SELECTION_RESTORATION

这是针对选区处理的wrapper,它会将当前选中的区域信息存储下来,在事务执行完毕之后再还原选区信息。

EVENT_SUPPRESSION

该wrapper会在事务处理时,初始化阶段暂停所有的事件监听,并将原始的事件监听状态传递到close阶段,等到close阶段再将事件监听的状态还原为初始值。

ON_DOM_READY_QUEUEING

该wrapper主要负责处理onDOMReady的回调,比如在执行挂载时,componentDidMount就是通过事务处理完毕后close阶段中,ON-DOM-READY-QUEUEING执行reactOnDOMReady.notifyAll实现的。

destructor

缓冲池对象的析构函数,内容很简单,释放了reactOnDOMReady资源,使之返回到缓冲池。

results matching ""

    No results matching ""