Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[工地] React中的Transaction模型 #3

Open
miniflycn opened this issue May 6, 2015 · 0 comments
Open

[工地] React中的Transaction模型 #3

miniflycn opened this issue May 6, 2015 · 0 comments

Comments

@miniflycn
Copy link
Owner

Transaction创建出一个黑盒,用于包裹任意方法,使得该方法的包裹在任意时候都正确触发,哪怕该方法在执行过程中抛错,如下图:

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

How to use?

// ES6 Object.assign,有点像jQuery.extend,具体参见:http://es6.ruanyifeng.com/#docs/object
var assign = require('react/lib/Object.assign'),
    Transaction = require("react/lib/Transaction");

// 要包裹的方法
function dosth() {
    console.log('dosth');
}

// 创建一个Transaction的子类
function MyTransaction() {
    this.reinitializeTransaction();
}

// mixin
assign(
    MyTransaction.prototype,
    Transaction.Mixin,
    {
        // 需要实现一个getTransactionWrappers方法,获取需要的包裹
        getTransactionWrappers: function() {
            return [{
                // 第一个包裹的初始化方法
                initialize: function (e) {
                    console.log('init first');
                },
                // 第一个包裹的完成方法
                close: function () {
                    console.log('close first');
                }
            }, {
                // 第二个包裹的初始化方法
                initialize: function (e) {
                    console.log('init second');
                },
                // 第二个包裹的完成方法
                close: function () {
                    console.log('close second');
                }
            }];
        }
    }
);

var myTransaction = new MyTransaction();

// 包裹dosth方法,scope是this
myTransaction.perform(dosth, this);
// init first
// init second
// dosth
// close first
// close second

从上面的例子,我们可以发现,在被包裹的函数运行前,会先运行wrappers的初始化方法,然后运行被包裹函数,最后运行wrappers结束方法。

// 前面省略
assign(
    MyTransaction.prototype,
    Transaction.Mixin,
    {
        getTransactionWrappers: function() {
            return [{
                initialize: function (e) {
                    // 让这里抛出错误
                    dosthundefined();
                    console.log('init first');
                },
                close: function () {
                    console.log('close first');
                }
            }, {
                initialize: function (e) {
                    console.log('init second');
                },
                close: function () {
                    console.log('close second');
                }
            }];
        }
    }
);

var myTransaction = new MyTransaction();

myTransaction.perform(dosth, this);
// init second
// close second
// Uncaught ReferenceError: dosthundefined is not defined

从上面的例子,我们可以发现,如果wrapper出现错误,则忽略该wrapper以及被包裹函数。

// 前面省略
function dosth() {
    dosthundefined();
    console.log('dosth');
}
// 中间省略
myTransaction.perform(dosth, this);
// init first
// init second
// close first
// close second
// Uncaught ReferenceError: dosthundefined is not defined

这个例子我们可以发现,如果被包裹函数出错,不会影响wrappers的运行。

具体实现请参考:https://github.com/facebook/react/blob/master/src/utils/Transaction.js ,比较简单。

Why we need Transaction?

由于虚拟DOMDOM两者是分别更新的,而两者是需要保持强一致性的,否则虚拟DOM中用户已经付款了,但页面却不显示用户付款了这就悲剧了!!!

那么哪里最有可能不可预知的错误,导致两者不一致呢?

回想一下同步逻辑:

JSX + 数据 -> 虚拟DOM -> 算出差异 -> 根据差异更新

错误最后可能出现在:

  1. 不可预知的数据,或者数据就是错误的,导致虚拟DOM生成时抛错
  2. 根据差异更新时,节点无法找到,或者DOM不符合预期

而Transaction正是为了解决虚拟DOMDOM同步的一致性而生的。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant