欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解react应用中的DOM DIFF算法

程序员文章站 2022-04-05 20:32:09
前言对我们搞前端的来说,目前最流行的两大前端框架毫无疑问当属react和vue,对于这两大框架,想必大家也是再熟悉不过了。然而,这两大框架无一例外的全部放弃使用传统的dom技术,却采用了以js为基础的...

前言

对我们搞前端的来说,目前最流行的两大前端框架毫无疑问当属react和vue,对于这两大框架,想必大家也是再熟悉不过了。然而,这两大框架无一例外的全部放弃使用传统的dom技术,却采用了以js为基础的virtual dom技术,也可称作虚拟dom。所以,到底什么是virtual dom?两大热门框架全部使用virtual dom的原因又是什么?接下来让我这个搞前端的人来好好地为您讲解一下dom diff算法的牛逼之处。

什么是virtual dom?

如字面意思所说,virtual dom即 虚拟dom,它的特点就是利用javascript来模拟dom结构,并且将dom的变化对比放在js层中进行比较。具体操作如下:

有朋友或许会有点迷惑,普通的html dom结构不好吗?通俗易懂,代码也更加简洁,为什么还需要采用嵌套递归的虚拟dom形式呢?其实这和普通dom在重新渲染的过程中非常消耗性能有关,dom操作看似简便,但其实效率相当低,这是因为如果是在需要频繁修改的真实dom中,看起来更加复杂的运用js结构的virtual dom效率会更高.

使用virtual dom的原因

dom 渲染页面的操作流程

  • 当浏览器通过域名从服务器拿到对应的html文件后,浏览器首先会进行构建dom树和cssom树,关于树的概念,学过数据结构与算法的同学或许对树的节点概念印象深刻。
  • 在html dom中,所有的事物都是节点,而dom是被视为节点树的html,并且,各个节点之间有着相应的层级关系。dom节点树和html中的标签一一对应,构成了dom树
  • html文件

详解react应用中的DOM DIFF算法

  • html dom树

详解react应用中的DOM DIFF算法

同样的。在css文档中,所有的元素也皆是节点,与html中的标签一一对应,构成了cssom树 如下图所示

详解react应用中的DOM DIFF算法

警告! 如果在构建dom树的过程中,有遇到js相关的内容时,dom树的构建会立即停止,这是由于,js可以对dom节点进行操作,浏览器为了防止js会对以完成的dom造成影响,会阻止dom树的构建,以节约资源。

在dom树和cssom树不断构建的过程中,渲染树也在逐渐形成,浏览器会根据所构建的渲染树进行网页布局和绘制流程,不断地进行网页的搭建。具体操作流程图如下:

详解react应用中的DOM DIFF算法

一般而言,对于页面渲染的常规操作,我们通常是操作dom,修改并重置innerhtml完成页面的渲染,每进行一次dom的更新操作,都会重新进行一次渲染流程,这个过程包含着页面的重绘和重排。

virtual dom的优势

详解react应用中的DOM DIFF算法

但是如果对于大型页面项目,或者具有多标签,多属性的网页而言,常规的dom操作实在是太耗时了,每次的简单修改都需要牵动大量的dom节点的重绘与重排,极大地降低了页面渲染效率.于是,当前端开发人员面对dom瓶颈一筹莫展的时候,virtual dom显示出了作为轻量级的javascript对象的极大优越性,顺利得到了了前端开发者的青睐。

在页面进行重新渲染的时候,virtual dom进行dom diff计算对比两次并发现其中的差异,只需要修改dom树中不同的部分即可.也可以理解为virtual dom做了一个中间件,先利用js修改virtual dom,在对比出差异后,将所有的更改加入页面的真实dom.所以说,virtual dom的最大优势就在于完全不用像原生dom,在对比之后还要进行dom的重建与创造,因为这对于大型项目的运行来说非常消耗性能,开销极大.由此可见,不论在什么体量的网页中,放弃传统dom采用virtual dom无疑是非常高效且绝佳的选择.

如何将dom用virtual dom 来表示

首先,在vscode中新建一个dom diff 项目,项目初始化,装好相应组件

由于是dom树,所以在将html转换成dom树时,要运用递归的形式,首先创建结点,其次设置属性,然后设置子节点

然后,在新建一个element.js文件进行向外输出,完成页面渲染

在控制台上得到真实dom

详解react应用中的DOM DIFF算法

页面渲染成功!????

详解react应用中的DOM DIFF算法

dom diff算法

在用户进行操作更改交互页面操作后,虚拟dom树上的节点会发生变化,然而此时真实节点却没有改变,为了使得更改与真实页面同步,我们会使用dom diff算法找出这两颗树的差异,然后产生差异补丁对象,再将差异补丁对象应用到真实的dom节点上去,于是完成了页面的渲染和更新。

传统的diff算法时间复杂度达到了o(n^3),若要满足每次都可以整体刷新页面的目的,这种指数型的增长的性能开销是无法满足性能要求的,于是,facebook的工程师对此进行了优化,通过制定diff策略将diff算法的复杂度降低到了o(n)

diff 策略

  • dom节点跨层级的操作特别少,所以可以忽略不计
  • 拥有相同类的两个组件将会产生相似的树形结构,拥有不同类的两个组件将会产生不同的树形结构
  • 同一层级的一组子节点,他们可以通过uuid进行区分

diff 粒度

由于diff的粒度不同,diff算法按照下面的顺序依次执行

  • tree diff
  • component diff
  • element diff

打补丁

我们根据diff策略以及react diff中的比对算法将两个虚拟dom通过深度优先遍历进行比较,如果有差异,就把所遍历到节点的索引值所对应的操作存储起来,也称为补丁对象(patches)

然后对真实的dom再次经过深度优先遍历,补丁对象中的索引就会和dom相对应,我们就完成了dom的更新操作。

结语
在互联网环境下,随时刷新交互页面是我们上网的常规操作,然而这一简单的操作却是多次算法优化的结果。dom diff的底层原理挺复杂,如果有感兴趣的朋友,可以自行搜索相关文献,因为本文只是浅析,所以太多方面就不赘述了,如果本文有知识错漏的地方,也欢迎指正!虚心接收一切合理批评!????

如果这篇文章有帮助到你对dom diff算法的理解,也希望您能为我点一个赞????,答主是刚入门的前端小白,每一个赞都是我前进的动力,我会持续更新掘金的博客的????

以上就是详解react应用中的dom diff算法的详细内容,更多关于react应用的dom diff算法的资料请关注其它相关文章!