Open switer opened 9 years ago
目前主流的一些MVVM框架(angular, vue.js)实现数据绑定(data-binding)都是使用 DOM 解析的方式。 但 Facebook 的 React 则颠覆性地采用 virtual dom 方式实现数据绑定。
angular
vue.js
此文主要比较 DOM parse 与 virtual dom 在实现方式上的差异。
以 way.js 为例:
way.js 在 document ready 事件触发后,调用 registerDependencies 来解析 HTML 模板,获取所有 DOM 上绑定的数据与行为
解析 HTML 模板
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 使用 Javascript 的基本数据类型(如: Array 与 Object)来描述 来 HTML 结构与 DOM 属性。
Array
Object
<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 操作。
vvv mark
此文主要比较 DOM parse 与 virtual dom 在实现方式上的差异。
DOM parse
以 way.js 为例:
way.js 在 document ready 事件触发后,调用 registerDependencies 来
解析 HTML 模板
,获取所有 DOM 上绑定的数据与行为way.js 使用属性选择器来获取
绑定声明
元素数据变化更新对应的 DOM 元素
updateDependencies 会调用 updateBindings 来处理使用 way-data 声明的绑定,updateBindings 根据更新 keypath 来获取声明相关绑定的 DOM 元素,最终会使用 .fromJSON() 来操作更新对象的 DOM 元素(innerHTML, value, ..。)
基于 DOM parse 实现的数据绑定,在解析绑定声明与数据变更后更新DOM的步骤都是关联着 DOM 操作,但 页面模板元素数量庞大的时候,性能问题就容易突显出来。
Virtual DOM
virtual dom 使用 Javascript 的基本数据类型(如:
Array
与Object
)来描述 来 HTML 结构与 DOM 属性。转换为 virtual dom 描述
React 在调用 setProps 或 setState 方法会后自动调用 .render() 方法来更新由 virtual dom 描述的模板:
调用 render 方法后,得到更新后的 virtual dom 对象,然后通过 react 的 diff 算法来计算需要更新 DOM 元素或 DOM 属性, 最终将这些差异更新 DOM 上,完成页面渲染。
而在一次数据更新中,两者执行的操作如下:
notice: 有些 DOM parse 的框架也会实现 diff(例如: vue.js),主要的 diff 逻辑在于已存在元素的复用上。react 的diff 算法包含了元素复用与元素属性的单独更新。
对于数据更新的页面渲染行为,无法直接地比较出两者性能差异。virtual dom 在性能上的优点在: