学新通技术网

使用虚拟DOM一定会比直接操作真实DOM快吗?

juejin 12 1
使用虚拟DOM一定会比直接操作真实DOM快吗?

前言

前一段时间有个朋友去面试被问到:使用虚拟DOM一定会比直接操作真实DOM快吗?

朋友很自信的回答:是的,一定。

然后,他就没有然后了。

就这个问题,我想聊一聊。

好像在大家惯有的思维模式下,我们普遍的认为,虚拟DOM一定会比原生DOM要快的多。

但实际上并不是这样。

我是一位React玩家,仅从React的角度来说 : React的官网可从来都没有说过虚拟DOM会比原生操作DOM更快。

虚拟DOM和原生操作DOM谁更快这个问题。如果要我来回答的话,一定是原生DOM比虚拟DOM更快性能更好。

值得注意的是,虚拟DOM并不是比原生DOM快,更确切的来说,虚拟DOM是比操作不当的原生DOM快。实际上,如果对原生DOM的操作得当的话,原生DOM的性能一定优于虚拟DOM。

我们来剖析一下。

虚拟DOM的真实面目(React版,不过Vue的也大同小异)

虚拟DOM本质上是一个对象。如下(👇)

    //这玩意就是虚拟DOM的真身 (React版)
        const vNode = {
            key:"d",  //是否有key,有则显示,无则显示null
            props:{
             //标签里是否子元素
             children:[
              {
               ....,
               ref:"null",
               type:'p'},
             ],
             onClick:() => {},  //标签上的事件
             className:"d-class", //标签上的属性
            }
            ref:"null",
            type:"div"
        }

这样的描述可能不够直观,我们使用真实DOM映射一下👇

真实DOM👇

    <div className="root" key="rootKey" ref="rootRef">
        <h1>昨晚上基金全是绿的,只有我的眼睛是红的</h1>
        <div className="top" onClick={() => console.log("工资一千五,心比美式苦")}>
          <p>今天你站上天台,我卧上轨道,来生我们有说有笑</p>
        </div>
    </div>

与之对应的虚拟DOM

 const VNode = {
  //第一层的div节点
   key:"rootKey",
   props:{
    className:"root"
   },
   //第二层的h1和div节点
   children:[
    //h1
     {
      children:"昨晚上基金全是绿的,只有我的眼睛是红的",
      type:"h1",
      props:{}
     },
     //div
     {
      type:"div",
      props:{
       className:"top",
       onClick:() => console.log("工资一千五,心比美式苦")
      },
      //div下的p标签
      children:[
        {
          type:"p",
          children:"今天你站上天台,我卧上轨道,来生我们有说有笑"
        }
      ]
     }
   ],
   ref:"rootRef",
   type:"div"
 }

以上,就是React版的虚拟DOM原形。

所谓的虚拟DOM,就是我们真实DOM在创建的时候,隐藏在真实DOM之下和真实DOM所对应的一个对象。这个对象,被我们称为虚拟DOM

虚拟DOM为什么而存在

其最核心的思想是提升开发效率而非提升性能

使用React/Vue这些框架的时候,我们不需要去考虑对DOM的操作,只需要关心数据的改变。我们以前还在使用JQ的时候,数据改变之后我们需要调用$("#id").append(node)等操作去手动追加DOM。而在使用React/Vue之后,我们只需要关心数据的改变。至于对DOM的一系列动作,在我们的数据改变之后,React/Vue会为我们代劳。这极大程度的提升了我们的开发效率。也是React/Vue的核心思想和初衷。

至于很多人都说,虚拟DOM会比操作原生DOM更快,这个说法并不全面。比如,首次渲染或者所有节点都需要进行更新的时候。这个时候采用虚拟DOM会比直接操作原生DOM多一重构建虚拟DOM树的操作。这会更大的占用内存和延长渲染时间。

举个例子

首次渲染👇不采用虚拟DOM的步骤

  1. 浏览器接受绘制指令
  2. 创建所有节点

首次渲染👇采用虚拟DOM的步骤

  1. 浏览器接受绘制指令
  2. 创建虚拟DOM
  3. 创建所有节点

不难发现,在首次渲染的时候,采用虚拟DOM会比不采用虚拟DOM要多一个创建虚拟DOM的步骤。

注意:虚拟DOM的存在,并不是免费的,比对新旧虚拟DOM树的差异会带来一定的性能开销。

虚拟DOM的优势在于我们更新节点时候。它会检查哪些节点需要更新。尽量复用已有DOM,减少DOM的删除和重新创建。并且这些操作我们是可以通过自己手动操作javascript底层api实现的。只是我们手动操作会非常耗费我们的时间和精力。这个工作由虚拟DOM代劳,会让我们开发更快速便捷。

举个例子👇

在采用虚拟DOM的前提下

假设我们有节点A,下辖两个子节点B/C.

然后我们删除了节点C

这个时候会有两棵虚拟DOM树,

一颗是修改前的,A->B/C。

另一颗是修改后的A->B。

diff算法会去比对两颗树的差异,然后发现A->B没有更改,那么A->B节点保留,C节点执行删除动作。

那么,A->B两个节点的删除和创建渲染操作就被省略了。

如果不采用虚拟DOM的话。使用JQ那时候的模板.

我们可能会把A->B/C三个节点全部删除.

再全都重新创建。而A->B是完全没有改动的。

他们的删除和创建则完全不必要。

框架的意义

我们需要知道:不论是React还是Vue或者是Angular。这些框架本身,都是基于原生的基础上创造的。它们,底层依赖的还是javascript,并不是一门新的语言。在他们的底层逻辑下。我们使用框架所做出的一切行为,都会被框架转化为对原生DOM的操作。框架,只是一个转化语法的工具。

既然原生DOM可以创造出这些框架。当然我们使用原生DOM自然是可以写出比这些框架更好的性能。

但是:为什么对原生DOM进行操作的性能明明可以比使用框架更好。为什么大家都在使用框架,而没有人去直接对原生DOM进行操作。

这背后涉及成本普适性

如果我们直接去操作真实DOM,当然,我们可以做到在性能上比虚拟DOM更快。但问题是,技术水准能做到这个地步的人,又有多少人呢。不说比虚拟DOM快。即使是做到和虚拟DOM不分上下的性能,拥有这种水平的前端玩家,也是寥寥无几。基于这样的客观情况下,框架的出现解决了这个问题。

框架存在的意义 : 在为我们提供只需要关注数据的前提下。框架本身已经做好了底层原理上的性能优化(包括但不限于,对DOM的调用,算法上的优化)已经是高度封装。这样就可以让我们使用一些简单的较为容易理解的技术去做我们原本做不到的事情。 这其实就像调用网上的第三方包,某一个功能,自己写是写不出来,写出来性能也不会很好。但是同样的功能,我们去网上引入其他大神已经封装完成的第三方包。我们就会用,功能就可以实现并且性能上也过得去。

如果让大家直接对DOM进行操作完成比框架更优秀的性能。这绝不是大多数人可以做到的。让大多数可以接受,框架需要做的,就是让大多数人使用尽量使用简单的技术,完成相对困难的操作。这是普适性

并且,如果完成同一个性能效果,需要我们去精通原生javascript学习框架上的一些简单的API和结构。明显后者的学习成本更低。如果说使用框架我们所能完成的某一阶段的性能所需要的学习成本是2个月的话。 那么学习javascript完成同一阶段的性能可能需要一年。

框架的初衷就是让用户使用尽量简单的技术,完成相对复杂的工作并提升一定的性能 (这其中包括但不限于:可维护性,可复用性,渲染效率等) 。这样,即使我们的水平不是很高,使用框架以后。项目在性能上也能过得去。

总结

  1. 虚拟DOM不一定会比操作原生DOM更快。
  2. 虚拟DOM的优势在于节点进行改动的时候尽量减少开销
  3. React从来没说过虚拟DOM会比原生更快。
  4. 框架的本质是提升开发效率,让我们的注意力更集中于数据

本文出至:学新通技术网

标签:

上一篇:HTML5的Link详细介绍

下一篇: