• 导赏!广美研究生导师带你看2018研究生毕业作品展 2019-04-20
  • 【沙湾风光】百花盛开 迎六月 2019-04-20
  • 【专题】传统文化点亮精彩生活 2019-04-10
  • 四川九寨沟发生特大泥石流 冲毁民房、省道205线被埋 2019-04-10
  • 探寻秘境阿勒泰《章棋的视频日志》 2019-04-06
  • 讲述波兰女子拯救百名犹太儿童的故事 美国教师获森德勒奖 2019-04-06
  • 一个理想的数列递减,看着就想笑,根本放不出什么屁来 2019-04-05
  • 给脑部做个“大扫除” 让大脑充分放松 2019-04-05
  • 海上洄游时 北海狗 连续两周深睡眠 2019-04-03
  • “石家庄太行大街发生重大事故”是谣言!传谣者被拘留 2019-04-01
  • 4号线为端午节“加班” 2019-04-01
  • 这18家小众颜高又难找的家居店,一次性帮你搜罗全了! 2019-03-24
  • “首届中国非处方药行业品牌宣传月”活动将在北京举办 2019-03-24
  • 《礼记》中的礼乐制度与“生活政治” 2019-03-23
  • 众泰T300 1.5L CVT车型上市 6.98万起 2019-03-23
  • 福建彩票36选7开奖结果:React事务机制解析

    版权声明:欢迎转载,转载请注明原始出处 //www.sde9.com/xiaomingelv/article/details/86183735

    广东快乐十分20选8计划 www.sde9.com 对react有一定了解的开发人员应该都听说过react的事务机制,这个机制几乎贯穿于react所有提供的方法,包括react中最常使用的setState函数

    那么,react的事务机制到底是一种什么样的机制呢,为了解释事务机制的实现原理,react源码中用注释画出了这样一幅图

    根据这幅图,我们可以这样理解事务,react中用事务执行方法,就是用wrapper(称之为套套吧)把方法包裹起来,然后每个wapper中都提供一个initialize方法和一个close方法,当需要使用事务调用一个方法,例如上图中的anyMethod时,使用事务提供的perform方法,将需要执行的方法传入,这个时候就会按顺序执行wrapper.initalize,anyMethod,wrapper.close,而且,事务还支持多个事务的嵌套,当执行方法被多个wapper包裹时,事务会先按顺序执行所有的initalize方法,再执行anyMethod,最后按顺序执行所有的close函数,例如上图就表示会按以下顺序执行wrapper1.initalize,wrapper2.initalize,anyMethod,wrapper1.close,wrapper2.close

    那么事务在react中到底是怎么应用的呢?我们透过下面这段代码来看看如何使用事务

    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);
        }
      },
    };

    代码不长,但确是react中用来控制渲染逻辑最关键的代码,此处只是为了展示事务的使用方法,我们无需关心代码做了些什么,我们可以看到上面的代码定义了一个叫ReactDefaultBatchingStrategyTransaction的构造函数,这个其实就是我们自定义的一个事务,并且在构造函数的原型上实现了一个叫getTransactionWrappers的接口,代码中的这个接口返回了一个数组,而这个数组的每一个项都包含了initalize和close方法,当调用perform方法时,事务会依次去调用这两个方法,而我们的看到的perform方法和构造函数中的reinitializeTransaction方法都是在Transaction.Mixin中定义的,这里面提供了实现事务所需要的所有基础功能,我们可以来看一下源代码的实现逻辑

    '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;
    

    这就是整个事务机制的实现代码,没有删减,逻辑非常清晰,也很简单,这里其实就是使用了原型模式,这个就是所有事务的原型,前面我们看到在自定义事务里面使用的perform方法和reinitializeTransaction方法都可以在这里面找到,其实核心原理就是定义一个原型,里面有一个用来存放wrappers(称之为套套吧)的抽象接口,会由继承于这个原型的子类覆盖,由子类来定义真正要执行的方法前后执行的所有东西,我们可以看到perform方法的逻辑其实也很清晰,就是先调用initializeAll方法执行所有的initialize方法,然后执行传入的主体方法,之后执行closeAll来执行所有的close方法,所以,看起来,目测也不是什么高深的东西,也就是在执行方法之前强行添加入口跟出口方法,代码比较简单,都加了注释,感兴趣的话可以自行了解一下

    这里面有个比较骚的操作在于,不管在initializeAll还是closeAll中,都是使用一个临时变量来标记当前的执行过程是否有异常,舍弃了用catch方法,改用在finally方法里面处理异常,官方的说法是捕获错误会使调试变的困难,具体原因应该是因为作为基础的原型类,此处不应该去捕获外部传入方法抛出的异常,应该让异常直接抛回外部,由外部函数自行处理,如果此处强行将异常捕获,确实会导致外部函数调试变的比较困难

    没有更多推荐了,广东快乐十分20选8计划

  • 导赏!广美研究生导师带你看2018研究生毕业作品展 2019-04-20
  • 【沙湾风光】百花盛开 迎六月 2019-04-20
  • 【专题】传统文化点亮精彩生活 2019-04-10
  • 四川九寨沟发生特大泥石流 冲毁民房、省道205线被埋 2019-04-10
  • 探寻秘境阿勒泰《章棋的视频日志》 2019-04-06
  • 讲述波兰女子拯救百名犹太儿童的故事 美国教师获森德勒奖 2019-04-06
  • 一个理想的数列递减,看着就想笑,根本放不出什么屁来 2019-04-05
  • 给脑部做个“大扫除” 让大脑充分放松 2019-04-05
  • 海上洄游时 北海狗 连续两周深睡眠 2019-04-03
  • “石家庄太行大街发生重大事故”是谣言!传谣者被拘留 2019-04-01
  • 4号线为端午节“加班” 2019-04-01
  • 这18家小众颜高又难找的家居店,一次性帮你搜罗全了! 2019-03-24
  • “首届中国非处方药行业品牌宣传月”活动将在北京举办 2019-03-24
  • 《礼记》中的礼乐制度与“生活政治” 2019-03-23
  • 众泰T300 1.5L CVT车型上市 6.98万起 2019-03-23
  • 云南时时彩每天多少期 pk10最多多少期不出 时时彩缩水工具手机端 双色球爱彩网波波预测 快乐10分技巧 半全场投注有望博大奖 大乐透中奖规则 九乐棋牌 南京体育彩票中心合作银行 爱彩网比分直播 打码赚钱是真的吗 p3试机号近10期体彩 德州扑克比赛视频 体彩网福利彩票走势图 排列五基本走势图 六合彩挂牌