React虚拟DOM的原理&&为什么使用虚拟DOM

来源:互联网 发布:c#集合和数组的区别 编辑:程序博客网 时间:2024/06/05 05:24

写在前边
本文是为理解虚拟DOM而整理的资料;方便日后查看;全部内容并非原创

一、什么是虚拟DOM?

传统的 DOM 操作是直接在 DOM 上操作的,当需要修改一系列元素中的值时,就会直接对 DOM 进行操作。而采用 Virtual DOM 则会对需要修改的 DOM 进行比较(DIFF),从而只选择需要修改的部分。也因此对于不需要大量修改 DOM 的应用来说,采用 Virtual DOM 并不会有优势。开发者就可以创建出可交互的 UI。

在React中,render执行的结果得到的并不是真正的DOM节点,结果仅仅是轻量级的JavaScript对象,我们称之为virtual DOM。

虚拟DOM是React的一大亮点,具有batching(批处理)和高效的Diff算法。这让我们可以无需担心性能问题而”毫无顾忌”的随时“刷新”整个页面,由虚拟 DOM来确保只对界面上真正变化的部分进行实际的DOM操作。在实际开发中基本无需关心虚拟DOM是如何运作的,但是理解其运行机制不仅有助于更好的理解React组件的生命周期,而且对于进一步优化 React程序也会有很大帮助。

二 .为什么需要虚拟DOM

DOM是很慢的,其元素非常庞大,页面的性能问题鲜有由JS引起的,大部分都是由DOM操作引起的。如果对前端工作进行抽象的话,主要就是维护状态和更新视图;而更新视图和维护状态都需要DOM操作。其实近年来,前端的框架主要发展方向就是解放DOM操作的复杂性。

在jQuery出现以前,我们直接操作DOM结构,这种方法复杂度高,兼容性也较差;有了jQuery强大的选择器以及高度封装的API,我们可以更方便的操作DOM,jQuery帮我们处理兼容性问题,同时也使DOM操作变得简单;但是聪明的程序员不可能满足于此,各种MVVM框架应运而生,有angularJS、avalon、vue.js等,MVVM使用数据双向绑定,使得我们完全不需要操作DOM了,更新了状态视图会自动更新,更新了视图数据状态也会自动更新,可以说MMVM使得前端的开发效率大幅提升,但是其大量的事件绑定使得其在复杂场景下的执行性能堪忧;有没有一种兼顾开发效率和执行效率的方案呢?ReactJS就是一种不错的方案,虽然其将JS代码和HTML代码混合在一起的设计有不少争议,但是其引入的Virtual DOM(虚拟DOM)却是得到大家的一致认同的。

三 、虚拟DOM 和 真实DOM的对比

DOM 完全不属于Javascript (也不在Javascript 引擎中存在).。Javascript 其实是一个非常独立的引擎,DOM其实是浏览器引出的一组让Javascript操作HTML文档的API而已。在即时编译的时代,调用DOM的开销是很大的。而Virtual DOM的执行完全都在Javascript 引擎中,完全不会有这个开销。

#四.理解虚拟DOM
虚拟的DOM的核心思想是:对复杂的文档DOM结构,提供一种方便的工具,进行最小化地DOM操作。这句话,也许过于抽象,却基本概况了虚拟DOM的设计思想

DOM很慢,而javascript很快,用javascript对象可以很容易地表示DOM节点。DOM节点包括标签、属性和子节点,通过VElement表示如下。

//虚拟dom,参数分别为标签名、属性对象、子DOM列表var VElement = function(tagName, props, children) {    //保证只能通过如下方式调用:new VElement    if (!(this instanceof VElement)) {        return new VElement(tagName, props, children);    }    //可以通过只传递tagName和children参数    if (util.isArray(props)) {        children = props;        props = {};    }    //设置虚拟dom的相关属性    this.tagName = tagName;    this.props = props || {};    this.children = children || [];    this.key = props ? props.key : void 666;    var count = 0;    util.each(this.children, function(child, i) {        if (child instanceof VElement) {            count += child.count;        } else {            children[i] = '' + child;        }        count++;    });    this.count = count;}

通过VElement,我们可以很简单地用javascript表示DOM结构。比如

var vdom = velement('div', { 'id': 'container' }, [    velement('h1', { style: 'color:red' }, ['simple virtual dom']),    velement('p', ['hello world']),    velement('ul', [velement('li', ['item #1']), velement('li', ['item #2'])]),]);

上面的javascript代码可以表示如下DOM结构:

<div id="container">    <h1 style="color:red">simple virtual dom</h1>    <p>hello world</p>    <ul>        <li>item #1</li>        <li>item #2</li>    </ul>   </div>

既然我们可以用JS对象表示DOM结构,那么当数据状态发生变化而需要改变DOM结构时,我们先通过JS对象表示的虚拟DOM计算出实际DOM需要做的最小变动,然后再操作实际DOM,从而避免了粗放式的DOM操作带来的性能问题。

如下图所示,两个虚拟DOM之间的差异已经标红:

虚拟DOM操作

原文链接:
http://www.ituring.com.cn/article/211352

转载知乎好文:
https://www.zhihu.com/question/29504639?sort=created

五、 虚拟DOM的原理

虚拟DOM作为中间操作层,相比渲染HTml来说,javascript计算的速度明显快于渲染DOM。
这里写图片描述


虚拟DOM则是在DOM的基础上建立了一个抽象层,我们对数据和状态所做的任何改动,都会被自动且高效的同步到虚拟DOM,最后再批量同步到DOM中。


虚拟DOM会使得App只关心数据和组件的执行结果,中间产生的DOM操作不需要App干预,而且通过虚拟DOM来生成DOM,会有一项非常可观收益——性能。

props(properties 特性)是在调用时候被调用者设置的,只设置一次,一般没有额外变化
可以把任意类型的数据传递给组件,尽可能的把props当做数据源,不要在组件内部设置props ,0.15.x已经废弃了setProps的方法。

1、this.props.children
2、this.props.xxx

state(状态)是在组件内部可以重复设置其值,是可以随意改变的

state用来确定组件的状态,不同状态可以展示不同的视图(控制下拉菜单的隐藏显示)
可以通过setState方法来设置state //this.setState(obj|function(state){})

一旦props或者state发生改变,组件都会重新渲染


所有人都知道DOM慢,渲染一个空的DIV,浏览器需要为这个DIV生成几百个属性,而虚拟DOM只有6个。

所以说减少不必要的重排重绘以及DOM读写能够对页面渲染性能有大幅提升

那么我们来看看虚拟DOM是怎么做的。React会在内存中维护一个虚拟DOM树,当我们对这个树进行读或写的时候,实际上是对虚拟DOM进行的。当数据变化时,然后React会自动更新虚拟DOM,然后拿新的虚拟DOM和旧的虚拟DOM进行对比,找到有变更的部分,得出一个Patch,然后将这个Patch放到一个队列里,最终批量更新这些Patch到DOM中。
这样的机制可以保证即便是根节点数据的变化,最终表现在DOM上的修改也只是受这个数据影响的部分,这样可以保证非常高效的渲染。
但也是有一定的缺陷的——首次渲染大量DOM时因为多了一层虚拟DOM的计算,会比innerHTML插入方式慢。

展示一个简单的react组件:

这里写图片描述

这是一个简单单完整的React组件【类】,细节大家先不用太在意细节,了解机制就可以。
props 主要作用是提供数据来源,可以简单的理解为 props 就是构造函数的参数。
state 唯一的作用是控制组件的表现,用来存放会随着交互变化状态,比如开关状态等。
JSX 做的事情就是根据 state 和 props 中的值,结合一些视图层面的逻辑,输出对应的 DOM 结构

原文链接:
http://www.cnblogs.com/purpleraintear/p/6040030.html

原创粉丝点击