The difference between Virtual DOM and DOM 虚拟DOM与DOM异同

原文链接:http://reactkungfu.com/2015/10/the-difference-between-virtual-dom-and-dom/

DOM

Just to get things straight - DOM stands for Document Object Model and is an abstraction of a structured text. For web developers, this text is an HTML code, and the DOM is simply called HTML DOM. Elements of HTML become nodes in the DOM.

So, while HTML is a text, the DOM is an in-memory representation of this text.

/* HTML是一个文本,DOM是这个文本在内存表现形式。*/

Compare it to a process being an instance of a program. You can have multiple processes of the same one program, just like you can have multiple DOMs of the same HTML (e.g. the same page loaded on many tabs).

The HTML DOM provides an interface (API) to traverse and modify the nodes. It contains methods like getElementById or removeChild. We usually use JavaScript language to work with the DOM, because… Well, nobody knows why :).

/* HTML DOM提供了一些接口来遍历和修改节点,其中包含getElementById或removeChild等方法。 但是我们通常使用JavaScript语言来处理DOM。*/

So, whenever we want to dynamicly change the content of the web page, we modify the DOM:

var item = document.getElementById("myLI");
item.parentNode.removeChild(item);

document is an abstraction of the root node, while getElementById, parentNode and removeChild are methods from HTML DOM API.

/* document 是对于根节点的一个抽象表示,而getElementById, parentNode and removeChild 是HTML DOM API的方法。 */

Issues

The HTML DOM is always tree-structured - which is allowed by the structure of HTML document. This is cool because we can traverse trees fairly easily. Unfortunately, easily doesn’t mean quickly here.

/* HTML DOM是树形结构。 这使得我们很容易地对树形结构进行遍历。 但是,这里的容易遍历并不意味着效率也同样很高。 */

The DOM trees are huge nowadays. Since we are more and more pushed towards dynamic web apps (Single Page Applications - SPAs), we need to modify the DOM tree incessantly and a lot. And this is a real performance and development pain.

/* 在当今DOM树十分巨大。随着动态web程序发展,我们需要不断地大量地修改DOM树。 这是性能和开发工作的痛点。 */

BTW. I myself managed to create a web page with a source of 5GB+. It wasn’t even that hard.

Consider a DOM made of thousands of divs. Remember, we are modern web developers, our app is very SPA! We have lots of methods that handle events - clicks, submits, type-ins… A typical jQuery-like event handler looks like this:

  • find every node interested on an event
  • update it if necessary

/* 上述是现代的网页开发人员经常遇到的两种事件处理程序。1.查找对应事件的节点。2.如果有必要,更新该节点。*/

Which has two problems:

  1. It’s hard to manage. Imagine that you have to tweak an event handler. If you lost the context, you have to dive really deep into the code to even know what’s going on. Both time-consuming and bug-risky.
  2. It’s inefficient. Do we really need to do all this findings manually? Maybe we can be smarter and tell in advance which nodes are to-be-updated?

/* 这带来两个问题,1.管理难度大。假如你必须处理某事件,当你失去了上下文,就必须深入到代码中,才能知道发生了什么。既耗时又有bug风险。2.开发效率低。我们是否真的需要手动完成所有这些工作?也许我们可以更聪明,提前告知哪些节点需要更新? */

Once again, React comes with a helping hand. The solution to problem 1 is declarativeness. Instead of low-level techniques like traversing the DOM tree manually, you simple declare how a component should look like. React does the low-level job for you - the HTML DOM API methods are called under the hood. React doesn’t want you to worry about it - eventually, the component will look like it should.

/* React对于问题1的解决方案是这样的,你不需要使用手动遍历DOM树这样的底层技术,而是简单地通过声明组件的外观。 React为你做了底层的工作。 */

But this doesn’t solve the performance issue. And this is exactly where the Virtual DOM comes into action.

/* 但是通过声明组件这并不能解决性能问题。性能问题是下面虚拟DOM完成的工作。 */

Virtual DOM

First of all - the Virtual DOM was not invented by React, but React uses it and provides it for free.

The Virtual DOM is an abstraction of the HTML DOM. It is lightweight and detached from the browser-specific implementation details. Since the DOM itself was already an abstraction, the virtual DOM is, in fact, an abstraction of an abstraction.

/* 虚拟DOM是对HTML DOM的抽象。它是轻量级的,并从浏览器特定的实现细节中分离出来。 由于DOM本身已经是一个抽象,所以虚拟DOM实际上是抽象的抽象。 */

Perhaps it’s better to think of the virtual DOM as React’s local and simplified copy of the HTML DOM. It allows React to do its computations within this abstract world and skip the “real” DOM operations, often slow and browser-specific.

/* 虚拟DOM可以看作是HTML DOM的React本地化和简化副本。 React可以在这个抽象的世界中执行它的计算,跳过“真正的”通常是缓慢的和特定于浏览器的DOM操作。 */

There’s no big difference between the “regular” DOM and the virtual DOM. This is why the JSX parts of the React code can look almost like pure HTML:

var CommentBox = React.createClass({
  render: function() {
    return (
      <div className="commentBox">
        Hello, world! I am a CommentBox.
      </div>
    );
  }
});

In most cases, when you have an HTML code and you want to make it a static React component, all you have to do is:

  1. Return the HTML code in render
  2. Replace class attribute name to className - because class is a reserved word in JavaScript.

/* 你有一个HTML代码,你想使它成为一个静态的React组件时,可以进行上述两步:1.在render中返回HTML代码。2.将class属性名称替换为className。 */

There are more, rather minor, differences between the DOMs:

  • Three attributes of the virtual DOM that don’t appear in “real” DOM - key, ref and dangerouslySetInnerHTML. See more.
  • React-ish virtual DOM introduced a few more constraints.

ReactElement vs ReactComponent

When talking about the virtual DOM, it’s important to see the difference between these two.

ReactElement

This is the primary type in React. React docs say:

A ReactElement is a light, stateless, immutable, virtual representation of a DOM Element.

/* ReactElement是React中的主要类型。文档中说:ReactElement是一个的轻量的,无状态的,不可变的,DOM元素的虚拟表示。 */

ReactElements lives in the virtual DOM. They make the basic nodes here. Their immutability makes them easy and fast to compare and update. This is the reason of great React performance.

/* ReactElements存在于虚拟DOM中。它们是基本的节点。他们的不变性使他们可以方便快捷地进行比较和更新。这是React性能强大的原因。 */

What can be a ReactElement? Almost every HTML tag - div, table, strong… If you wish, see the whole list.

Once defined, ReactElements can be render into the “real” DOM. This is the moment when React ceases to control the elements. They become slow, boring DOM nodes:

/* 一旦定义,ReactElements可以渲染到“真实”的DOM。在此时刻,React停止控制元素。它们被转化成DOM节点。 */

var root = React.createElement('div');
ReactDOM.render(root, document.getElementById('example'));
// If you are surprised by the fact that `render` 
// comes from `ReactDOM` package, see the Post Scriptum.

JSX compiles HTML tags to ReactElements. So this is equivalent to the above:

var root = <div />;
ReactDOM.render(root, document.getElementById('example'));

Once again - ReactElements are the basic items in React-ish virtual DOM. However, they are stateless, therefore don’t seem to be very helpful for us, the programmers. We would rather work on the class-like pieces of HTML, with kind-of-variables and kind-of-constants - don’t we? And here we come to…

/* ReactElements是React-ish虚拟DOM中的基本项目。但是,他们是无状态的,所以对程序员来说,我们似乎不是很有帮助。我们宁愿使用类似变量和常量来处理类的HTML片段。 */

ReactComponent

What differs ReactComponent from ReactElement is - ReactComponents are stateful.

/* ReactComponent与ReactElement不同之处在于 - ReactComponents是有状态的。 */

We usually use React.createClass method to define one:

var CommentBox = React.createClass({
  render: function() {
    return (
      <div className="commentBox">
        Hello, world! I am a CommentBox.
      </div>
    );
  }
});

Your HTML-like blocks returned from render method can have a state. And the best thing is (I bet you already know it, this is why React is so cool!) - whenever the state changes, the component is rerendered:

var Timer = React.createClass({
  getInitialState: function() {
    return {secondsElapsed: 0};
  },
  tick: function() {
    this.setState({secondsElapsed: this.state.secondsElapsed + 1});
  },
  componentDidMount: function() {
    this.interval = setInterval(this.tick, 1000);
  },
  componentWillUnmount: function() {
    clearInterval(this.interval);
  },
  render: function() {
    return (
      <div>Seconds Elapsed: {this.state.secondsElapsed}</div>
    );
  }
});

ReactComponents turned out to be a great tool for designing dynamic HTML. They don’t have the access to the virtual DOM, but they can be easily converted to ReactElements:

/* ReactComponents是设计动态HTML的好工具。 他们没有虚拟DOM的访问权限,但可以很容易地将其转换为ReactElements。 */

var element = React.createElement(MyComponent);
// or equivalently, with JSX
var element = <MyComponent />;

What makes the difference?

ReactComponents are great, we would love to have plenty of them since they are easy to manage. But they have no access to the virtual DOM - and we would like to do as much as possible there.

/* ReactComponents很容易管理,但无法访问虚拟DOM。 */

Whenever a ReactComponent is changing the state, we want to make as little changes to the “real” DOM as possible. So this is how React deals with it. The ReactComponent is converted to the ReactElement. Now the ReactElement can be inserted to the virtual DOM, compared and updated fast and easily. How exactly - well, that’s the job of the diff algorithm. The point is - it’s done faster than it would be in the “regular” DOM.

/* 每当ReactComponent组件改变状态时,我们希望尽可能少地改变“真实”的DOM。 这里就是React所做的事: ReactComponent转换为ReactElement。 当ReactElement被插入到虚拟DOM中时,可以简单快速地比较和更新。 这是由差异算法来实现的。 重点是 - 它比“常规”DOM的速度要快。 */

When React knows the diff - it’s converted to the low-level (HTML DOM) code, which is executed in the DOM. This code is optimised per browser.

/* 当React监听到DOM的差异 - ReactElement会被转换成根据浏览器进行优化的在DOM中执行的代码。 */

Summary

Is virtual DOM really the feature to boast on the main page? I would say so. In practise, React performance is absolutely high, and the virtual DOM is surely very helpful here.

/* 在实际运行中,React性能绝对高 */

PS. In case you didn’t notice - since the last week, when React 0.14 was released, the DOM-related parts of React were extracted from the react package. Now there is a separate package react-dom. You can read more in the newest changelog.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270