抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

虚拟DOM和diff算法

在学习 React 之前,我们需要先了解两个概念:虚拟DOM、diff算法。

虚拟DOM

问题描述

假设我们的数据发生一点点的变化,也会被强制重建整颗DOM树,这么做,会涉及到很多元素的重绘和重排,导致性能浪费严重。

解决上述问题的思路

实现按需更新页面上的元素即可。也就是说,把 需要修改的元素,所对应的 DOM 元素重新构建;其他没有变化的数据,所对应的 DOM 节点不需要被强制更新。

具体实现方案:(如何按需更新页面上的元素)

只需要拿到 页面更新前的 内存中的DOM树,同时再拿到 页面更新前的 新渲染出来的 内存DOM树;然后,对比这两颗新旧DOM树,找到那些需要被重新创建和修改的元素即可。这样就能实现 DOM 的按需更新

如何拿到这两棵DOM树:(即:如何从浏览器的内存住哪个获取到 浏览器私有的那两颗DOM树?)

如果要拿到浏览器私有的DOM树,那我们必须调用浏览器提供的相关JS的API才行。但是问题来了,浏览器并没有提供这样的API。既然如此,那我们可以自己模拟这两颗 新旧DOM树。

如何自己模拟这两颗 新旧DOM树:(即:如何自己模拟一个DOM节点?)

这里涉及到手动模拟DOM树的原理:使用 JS 创建一个对象,用和这个对象来模拟每一个DOM节点;然后在每个DOM节点中,又提供了类似于 children 这样的属性来描述当前DOM的子节点。这样的话,当DOM节点形成了嵌套关系,就模拟出了一颗 DOM 树。

总结

  • 虚拟DOM的本质:使用 JS 对象模拟DOM树。

  • 虚拟DOM的目的:为了实现 DOM 节点的高效更新。

React内部已经帮我们实现了虚拟DOM,初学者掌握如何调用即可。

diff算法

怎么实现 两颗新旧DOM树的对比 呢?这里就涉及到了 diff算法。常见的 diff算法如下:

  • tree diff:新旧DOM树,逐层对比的方式,就叫做 tree diff。每当我们从前到后,把所有层的节点对比完后,必然能够找到那些 需要被更新的元素。

  • component diff:在对比每一层的时候,组件之间的对比,叫做 component diff。当对比组件的时候,如果两个组件的类型相同,则暂时认为这个组件不需要被更新,如果组件的类型不同,则立即将旧组件移除,新建一个组件,替换到被移除的位置。

  • element diff:在组件中,每个元素之间也要进行对比,那么,元素级别的对比,叫做 element diff。

  • key:key这个属性,可以把 页面上的 DOM节点 和 虚拟DOM中的对象,做一层关联关系。

React 介绍

React 是什么

  • Facebook 开源的一个JS库。

  • 一个用于动态构建用户界面的JS库。

React 的特点

  • Declarative(声明式编码)

  • Component-Based(组件化编码)

  • Learn Once, Write Anywhere(支持客户端、服务器端渲染)

  • 高效的DOM Diff算法,最小化页面重绘

  • 单向数据流

React高效的原因

  • 虚拟(virtual)DOM,不总是直接操作DOM

  • 高效的DOM Diff算法,最小化页面重绘(即“局部渲染”)。

虚拟DOM指的是:在真实DOM的上一层映射一层虚拟DOM。我们操作的是映射关系,而不是真实的DOM。假设页面的样式做了修改(比如新增了一个标签),此时修改的是虚拟DOM的样式,真实的DOM并未发生变化。那什么时候,真实的DOM会发生变化呢? 当我把所有的内容操作完之后,转化为真实的DOM,此时要打包统一的渲染页面,于是真实的DOM发生变化,然后渲染一次。 这样做的话,可以减少页面的渲染次数。

相关网址

官网截图:

20190208_1057.png

上方截图中,有一个特性是“Learn Once, Write Anywhere”。这里的 “Anywhere” 其实指的是两个地方:一个是浏览器端,一个是服务器端。后者指的是,React支持在服务器端渲染页面

生态介绍

  • Vue生态:Vue + Vue-Router + Vuex + Axios + Babel + Webpack

  • React生态:React + React-Router + Redux + Axios + Babel + Webpack

React 模块化、组件化