React transaction mechanism to resolve

Copyright Notice: Welcome to reprint, please indicate the original source https://blog.csdn.net/xiaomingelv/article/details/86183735

Have a certain understanding of the developers react transaction mechanism react should have heard of this mechanism almost throughout all react methods provided, including setState react in the most commonly used functions

So, transaction mechanism react in the end is what kind of mechanism for it, in order to explain the mechanism of realization of the principle matters, react with the source code annotated to draw such a picture

According to this figure, we can understand the transaction, the transaction by REACT execution method is to use warpper (it is called a condom) wrapped up the methods, and are each provided wapper an initialize method, and a close method, when it is desired use transaction call a method, for example, the image above anyMethod, perform transactions using a method provided, the method needs to perform passed, this time will be executed in order wrapper.initalize, anyMethod, wrapper.close, but the transaction still a plurality of support nested transactions, the method is performed when a plurality of wrapped wapper, transactions are executed sequentially before all initalize method, and then performing anyMethod, and finally in order to perform all the close function, for example the following would be represented on FIG. sequentially performed wrapper1.initalize, wrapper2.initalize, anyMethod, wrapper1.close, wrapper2.close

Then the transaction react in the end is how the application of it? Us through the following code to see how to use the transaction

var ReactUpdates = require('ReactUpdates');
var Transaction = require('Transaction');

var emptyFunction = require('emptyFunction');

//第二个wrapper
var RESET_BATCHED_UPDATES = {
  initialize: emptyFunction,
  close: function() {
    ReactDefaultBatchingStrategy.isBatchingUpdates = false;
  },
};

//第一个wrapper
var FLUSH_BATCHED_UPDATES = {
  initialize: emptyFunction,
  close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates),
};

//wrapper列表
var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];

//事务构造函数
function ReactDefaultBatchingStrategyTransaction() {
//原型中定义的初始化方法
  this.reinitializeTransaction();
}

//继承原型
Object.assign(
  ReactDefaultBatchingStrategyTransaction.prototype,
  Transaction.Mixin,
  {
    getTransactionWrappers: function() {
      return TRANSACTION_WRAPPERS;
    },
  }
);

//新建一个事务
var transaction = new ReactDefaultBatchingStrategyTransaction();

var ReactDefaultBatchingStrategy = {
  isBatchingUpdates: false,

  /**
   * Call the provided function in a context within which calls to `setState`
   * and friends are batched such that components aren't updated unnecessarily.
   */
  batchedUpdates: function(callback, a, b, c, d, e) {
    var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;

    ReactDefaultBatchingStrategy.isBatchingUpdates = true;

    // The code is written this way to avoid extra allocations
    if (alreadyBatchingUpdates) {
      callback(a, b, c, d, e);
    } else {
      //在这个地方调用事务,callback是从外部传入的方法,此处无需关心callback,只需要知道它是一个待执行方法即可
      transaction.perform(callback, null, a, b, c, d, e);
    }
  },
};

The code is not long, but they are used to control the rendering logic react in the most critical code here just to show use of the transaction, we do not care about the code done, we can see that the above code defines a call ReactDefaultBatchingStrategyTransaction constructor, this is actually our custom a transaction, and implemented on a prototype constructor interface called getTransactionWrappers, the code in this interface returns an array, the array of each item contains a initalize and close method, when invoked perform method, the transaction will turn to call these two methods, and the way we see reinitializeTransaction perform method and the constructor is defined in Transaction.Mixin, which provides an implementation inside All firms need basic functions, we can look at the implementation logic source code

'use strict';
var invariant = require('invariant');

var Mixin = {
  //事务初始化函数
  reinitializeTransaction: function() {
    this.transactionWrappers = this.getTransactionWrappers();
    if (this.wrapperInitData) {
      this.wrapperInitData.length = 0;
    } else {
      this.wrapperInitData = [];
    }
    this._isInTransaction = false;
  },
  _isInTransaction: false,

  //抽象接口,此处的getTransactionWrappers方法将会被外部定义的getTransactionWrappers方法所覆盖
  getTransactionWrappers: null,

  isInTransaction: function() {
    return !!this._isInTransaction;
  },

  perform: function(method, scope, a, b, c, d, e, f) {
    var errorThrown;
    var ret;
    try {
      this._isInTransaction = true;
      errorThrown = true;
      //执行所有的initalize方法
      this.initializeAll(0);
      //执行真正的方法
      ret = method.call(scope, a, b, c, d, e, f);
      errorThrown = false;
    } finally {
      try {
        if (errorThrown) {
          try {
            this.closeAll(0);
          } catch (err) {
          }
        } else {
          //正常状态下执行所有close方法
          this.closeAll(0);
        }
      } finally {
        this._isInTransaction = false;
      }
    }
    return ret;
  },

//执行所有wrapper中的initialize函数
  initializeAll: function(startIndex) {
    var transactionWrappers = this.transactionWrappers;
    for (var i = startIndex; i < transactionWrappers.length; i++) {
      var wrapper = transactionWrappers[i];
      try {
        //定义一个初始值,当finally里面匹配到this.wrapperInitData[i]未改变时,会忽略此项,从下一个项开始重新执行一次初始化,这么做的原因。。。官方解释为用catch使调试变的复杂,开心就好
        this.wrapperInitData[i] = Transaction.OBSERVED_ERROR;
        //执行initialize方法
        this.wrapperInitData[i] = wrapper.initialize ?
          wrapper.initialize.call(this) :
          null;
      } finally {
        if (this.wrapperInitData[i] === Transaction.OBSERVED_ERROR) {
          try {
            this.initializeAll(i + 1);
          } catch (err) {
          }
        }
      }
    }
  },
//执行所有wrapper中的close函数
  closeAll: function(startIndex) {
    invariant(
      this.isInTransaction(),
      'Transaction.closeAll(): Cannot close transaction when none are open.'
    );
    var transactionWrappers = this.transactionWrappers;
    for (var i = startIndex; i < transactionWrappers.length; i++) {
      var wrapper = transactionWrappers[i];
      var initData = this.wrapperInitData[i];
      var errorThrown;
      try {
        //标记是否有执行异常,这么做的原因。。。官方解释为用catch使调试变的复杂,开心就好
        errorThrown = true;
        //执行close方法
        if (initData !== Transaction.OBSERVED_ERROR && wrapper.close) {
          wrapper.close.call(this, initData);
        }
        errorThrown = false;
      } finally {
        //存在异常异常
        if (errorThrown) {
          try {
            this.closeAll(i + 1);
          } catch (e) {
          }
        }
      }
    }
    this.wrapperInitData.length = 0;
  },
};

var Transaction = {
  Mixin: Mixin,
  OBSERVED_ERROR: {},
};

module.exports = Transaction;

This is the code that implements the entire transaction mechanisms, not cut, the logic is very clear, very simple, in fact, here is the use of the prototype model, this is the prototype of all transactions, perform in front of us to see ways to customize and use inside a transaction reinitializeTransaction method can be found there, in fact, the core principle is the definition of a prototype, which has a store for wrappers (called a condom, right) abstract interface, it will be covered by a subclass inherited from the prototype to the subclass everything before and after the implementation of the method of execution is defined to be true, we can see the logic perform the method is actually very clear, it is to first call initializeAll method of performing all of the initialize method, and then perform the incoming body of the method, after performing closeAll to perform all the close method, therefore, it seems, is not a profound visual thing, that is, before the implementation of the method to force entry is added with export method, the code is relatively simple, have added a note of interest, then you can look at yourself

And there are a relatively Sao operation is that, no matter initializeAll or closeAll in, are using a temporary variable to mark the current execution process is abnormal, abandoned by catch method, use the method to handle exceptions in it finally official argument is wrong capture will become difficult to debug, specific reasons should be because as a prototype class-based, here should not go to capture incoming external method throws exception, an exception should be allowed to directly thrown back outside the discretion of the external function If forced to catch the exception here, does cause external function debugging becomes more difficult

Guess you like

Origin blog.csdn.net/xiaomingelv/article/details/86183735