switer / switer.github.io

Personal homepage
https://switer.github.io
5 stars 0 forks source link

Compare DOM parse data binding to virtual dom #24

Open switer opened 9 years ago

switer commented 9 years ago

目前主流的一些MVVM框架(angular, vue.js)实现数据绑定(data-binding)都是使用 DOM 解析的方式。 但 Facebook 的 React 则颠覆性地采用 virtual dom 方式实现数据绑定。

此文主要比较 DOM parsevirtual dom 在实现方式上的差异。

DOM parse

way.js 为例:

way.js 在 document ready 事件触发后,调用 registerDependencies 来解析 HTML 模板,获取所有 DOM 上绑定的数据与行为

WAY.prototype.registerDependencies = function() {
    this.registerBindings();
    this.registerRepeats();
}

way.js 使用属性选择器来获取绑定声明元素

数据变化更新对应的 DOM 元素

WAY.prototype.set = function(selector, value, options) {
  ...
  _json.set(self.data, selector, value); // 更新数据
  ...
  self.updateDependencies(selector, value); // 处理绑定依赖,在这里更新 DOM
  ...
}

updateDependencies 会调用 updateBindings 来处理使用 way-data 声明的绑定,updateBindings 根据更新 keypath 来获取声明相关绑定的 DOM 元素,最终会使用 .fromJSON() 来操作更新对象的 DOM 元素(innerHTML, value, ..。)

WAY.prototype.updateBindings = function(selector) {
    ...
    self.dom(element).fromJSON(self.data);
    ...
}

基于 DOM parse 实现的数据绑定,在解析绑定声明数据变更后更新DOM的步骤都是关联着 DOM 操作,但 页面模板元素数量庞大的时候,性能问题就容易突显出来。

Virtual DOM

virtual dom 使用 Javascript 的基本数据类型(如: ArrayObject)来描述 来 HTML 结构与 DOM 属性。

<div style="color: blue" title="Hello world"></div>

转换为 virtual dom 描述

React.createElement('div', {
    style: {
        color: "blue"
    },
    title: "Hello world"
});

React 在调用 setProps 或 setState 方法会后自动调用 .render() 方法来更新由 virtual dom 描述的模板:

<div style={ {color: this.state.active? 'blue':'gray'} } 
    title="Hello world"
>{this.state.title}</div>
this.setState({
    active: false,
    title: 'Disable !'
})
render: function () {
    return React.createElement('div', {
        style: {
            color: this.state.active? 'blue':'gray'
        },
        title: this.props.title
    }, this.state.title);
}

调用 render 方法后,得到更新后的 virtual dom 对象,然后通过 react 的 diff 算法来计算需要更新 DOM 元素或 DOM 属性, 最终将这些差异更新 DOM 上,完成页面渲染。

<div style="color: gray" title="Hello world">Disable !</div>

而在一次数据更新中,两者执行的操作如下:

notice: 有些 DOM parse 的框架也会实现 diff(例如: vue.js),主要的 diff 逻辑在于已存在元素的复用上。react 的diff 算法包含了元素复用与元素属性的单独更新。

对于数据更新的页面渲染行为,无法直接地比较出两者性能差异。virtual dom 在性能上的优点在:

virtual dom 没有模板解析过程,相比起 DOM parse 省却了 HTML 模板解析过程中的大量 DOM 操作。

xiaokaike commented 9 years ago

vvv mark