事务一般出现在数据库,能保证出错的时候进行rollbakc恢复。以下是React源码中的事务(Transaction)部分(部分解析直接注释在源码里)。
'use strict';
var _prodInvariant = require('./reactProdInvariant');
var invariant = require('fbjs/lib/invariant');
var OBSERVED_ERROR = {};
/**
* <pre>
* wrappers (injected at creation time)
* + +
* | |
* +-----------------|--------|--------------+
* | v | |
* | +---------------+ | |
* | +--| wrapper1 |---|----+ |
* | | +---------------+ v | |
* | | +-------------+ | |
* | | +----| wrapper2 |--------+ |
* | | | +-------------+ | | |
* | | | | | |
* | v v v v | wrapper
* | +---+ +---+ +---------+ +---+ +---+ | invariants
* perform(anyMethod) | | | | | | | | | | | | maintained
* +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
* | | | | | | | | | | | |
* | | | | | | | | | | | |
* | | | | | | | | | | | |
* | +---+ +---+ +---------+ +---+ +---+ |
* | initialize close |
* +-----------------------------------------+
* </pre>
*/
var TransactionImpl = {
reinitializeTransaction: function () {
//可以理解Transaction为抽象类,this.getTransactionWrappers()是Transaction的抽象方法
this.transactionWrappers = this.getTransactionWrappers();
if (this.wrapperInitData) {
this.wrapperInitData.length = 0;
} else {
this.wrapperInitData = [];
}
this._isInTransaction = false;
},
_isInTransaction: false,
getTransactionWrappers: null,
isInTransaction: function () {
return !!this._isInTransaction;
},
/*
*method:要执行的目标函数
*scope:目标函数执行的this环境
*abcdef:method的参数,可以使用arguments获取,但是react框架认为函数不会超过6个参数,所以就规定了6个参数
*/
perform: function (method, scope, a, b, c, d, e, f) {
!!this.isInTransaction() ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Transaction.perform(...): Cannot initialize a transaction when there is already an outstanding transaction.') : _prodInvariant('27') : void 0;
var errorThrown;
var ret;
try {
//用来记录当前事务是否正在执行,相当于加锁了,保证当前的Transaction正在perform的同时不会再次被perform。
this._isInTransaction = true;
errorThrown = true;
this.initializeAll(0);
ret = method.call(scope, a, b, c, d, e, f); //记录函数执行的返回值
errorThrown = false; //用于记录wrapper初始化和目标函数执行的过程是否报错
} finally {
try {
if (errorThrown) {
try {
this.closeAll(0);
} catch (err) {}
} else {
this.closeAll(0);
}
} finally {
this._isInTransaction = false; //解锁
}
}
return ret;
},
initializeAll: function (startIndex) {
var transactionWrappers = this.transactionWrappers;
for (var i = startIndex; i < transactionWrappers.length; i++) {
var wrapper = transactionWrappers[i];
try {
this.wrapperInitData[i] = OBSERVED_ERROR;
this.wrapperInitData[i] = wrapper.initialize ? wrapper.initialize.call(this) : null;
} finally {
if (this.wrapperInitData[i] === OBSERVED_ERROR) {
try {
this.initializeAll(i + 1);
} catch (err) {}
}
}
}
},
closeAll: function (startIndex) {
!this.isInTransaction() ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Transaction.closeAll(): Cannot close transaction when none are open.') : _prodInvariant('28') : void 0;
var transactionWrappers = this.transactionWrappers;
for (var i = startIndex; i < transactionWrappers.length; i++) {
var wrapper = transactionWrappers[i];
var initData = this.wrapperInitData[i];
var errorThrown;
try {
errorThrown = true;
if (initData !== 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;
}
};
module.exports = TransactionImpl;
开头引入的两个文件分别用于生产环境下和开发环境下的错误抛出
图中可以看出,所有放入事务队列中的函数都会用wrapper包装,并且在函数真正执行前和后分别要执行initialize()和close()。
perform方法是执行被包装目标函数的主要方法,其作用类似于method.call,当然它还处理了initialize方法(在被包装目标函数执行之前被指定的方法)和close方法(被包装函数执行之后被指定的方法)。
initializeAll在perform中被调用,它用于处理所有Wrapper的initialize方法。
closeAll也在perform中被调用,它用于处理所有Wrapper的close方法。
reinitializeTransaction,清除、重置当前Transaction的残余数据,在Transaction的实现中,上一次调用后的一些残余数据需要通过这个方法来清除。
以上源码中大多数都是在抛出错误,剔除错误处理部分,就好理解的多。
(ps: 从现在开始想每天坚持写一篇技术总结,现在还是小白阶段,写的不好。如果有幸有人可以看到,欢迎批评指正。目前主要针对前端相关和可视化方面,也请你多多指点,留言给予一些学习建议和一些学习资源的分享以及一些学习网站的推荐,共同进步)