最新公告
  • 欢迎您光临网站无忧模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • vue+diff+最全讲解

    正文概述 掘金(After_school)   2021-04-28   458

    前言

    我们都知道,浏览器的DOM操作是十分昂贵、十分浪费性能的!

    Vue通过虚拟DOM的方式优化了这部分性能浪费,它的核心原理是通过diff算法对比新老节点之间的差异,判断哪些节点可以复用,减少DOM操作的浪费,提升性能!

    所以,diff算法的本质就是--找出两个vnode之间的差异,尽可能复用节点!

    为何采用虚拟DOM

    vue的编写者其实给出了自己的答案:

    1、为函数式的UI编程方式打开了大门;

    2、可以渲染到DOM以外的backend。

    针对这两点谈谈自己的理解:

    1、为函数式的UI编程方式打开了大门;

    每次生成新的ui就需要重新刷新页面代价太过昂贵,虚拟DOM以及diff算法的引入可以最大限度的复用旧的DOM,使得渲染性能大幅提升。

    2、可以渲染到DOM以外的backend。

    有了虚拟DOM就可以轻松实现跨平台,多平台的core都相同,只是在render到具体平台的时候采取不同的render就好了

    前面介绍了diff算法的本质就是比较vnode的异同,那么vnode都包含哪些属性呢?

    其实仔细思考下,一个dom节点主要包含三个部分:

    <div id='node'>
       <p id='diff'>哈哈</p>
     </div>
    

    1、自身的标签名(div)

    2、自身的属性(id='node')

    3、子节点(p)

    所以我们可以设计如下的对象结构表示一个dom节点

    const oldVnode = {
      tag:'div',
      attrs:{id:'node'},
      children:[{ tag:'p',attrs:{id:'diff'},children:['哈哈']}]
    }
    

    当用户对界面进行操作,比如把div的id改为dom ,将子节点span的文本子节点‘哈哈’改为‘嘻嘻’,那么我们可以得到如下vnode

    const newVnode = {
      tag:'div',
      attrs:{id:'dom'},
      children:[{ tag:'p',attrs:{id:'diff'},children:['嘻嘻']}]
    }
    

    那么我们运行diff(oldVnode,newVnode),就能知道oldVnode和newVnode之间的差异如下: div的id改为dom span的文本子‘哈哈’改为‘嘻嘻 知道了差异部分,我们就能更新视图,伪代码如下:

    document.getElementById("app").setAttribute('id', 'app2')// id 改为 app2
    document.getElementById("child").firstChild.textContent ='2' //1 改为 2
    

    上面整个过程就是整个diff过程的预演,真实的diff过程跟上面整个过程大同小异,只是需要考虑更多的边界条件!下面让我们来了解一下真正的diff算法

    diff算法执行的时机

    在了解diff算法的执行时机之前,我们先简单看一下vue框架的渲染过程,如下图所示:

    vue+diff+最全讲解

    从图中可以看出,当我们更新data中响应式数据的值时,vue的patch()函数执行过程中会通过diff算法对比新老vnode的异同,然后更新vnode树,当对比完成以后会统一将有变更的虚拟接点渲染成前端页面。

    diff算法

    diff算法包括二部分:

    1、vnode树的遍历

    2、节点对比,只对比同层的节点

    vue+diff+最全讲解

    vnode树的遍历:

    虚拟DOM说到底只是一颗树形结构,对于树的遍历我们知道有深度遍历和广度遍历

    目前,不管是vue还是react,采用的都是深度遍历算法

    深度遍历需要栈结构,可以通过递归(内核维护调用栈)的方式实现,也可以采用人为构造栈,然后循环栈完成深度遍历。通常深度优先搜索法不全部保留结点,扩展完的结点从栈中弹出删去,这样,在栈中存储的结点数就是深度值,因此它占用空间较少。

    节点对比:

    对于相同的节点,继续比较子节点:

    同一级子元素新老虚拟DOM列表分别设置startIndex和endIndex,首先,旧首和新首对比,旧尾和新尾对比,然后交叉判断startIndex和endIndex是否是相同元素

    对比的结果有三种情况:相同、新增、删除、移位

    相同

    保持不变

    新增

    老的startIndex不动,新的startIndex移位,并在老的startIndex元素前插入

    移位:

    新startIndex和老startIndex或者新endIndex和老endIndex相同,只要移动startIndex或者endIndex就可以了;

    新startIndex和老endIndex相同,新startIndex++,老endIndex--,将老endIndex的ele插入到老startIndex的ele前面

    新endIndex和老startIndex相同,新endIndex--,老startIndex++,将老的startIndex的ele插入到老endIndex的ele的后面

    新startIndex的key匹配到老的vnode的key,将老vnode的ele插入到老startIndex的ele前面,还有一个操作:将老vnode标记位undefined,(oldCh[idxInOld] = undefined)

    删除

    等新startIndex和新endIndex合拢,老startIndex和老endIndex之间的非undefined的vnode的ele全部删除,undefined的node代表已经处理过了(移位)

    举例说明

    1、oldVnode与newVnode头指针指向的节点相同,DOM节点保持不变,oldVnode与newVnode头指针分别向后前一位。

    vue+diff+最全讲解

    2、oldVnode与newVnode尾指针指向的节点相同,DOM节点保持不变,oldVnode与newVnode尾指针分别向后退一位。

    vue+diff+最全讲解

    3、newVnode尾指针节点与oldVnode头指针节点是同一个节点,将oldVnode头指针对应的DOM插入到oldVnode尾指针对应的DOM之后,newVnode尾指针向后退一位,oldVnode头指针向前移一位。

    vue+diff+最全讲解

    (4)oldVnode包含newVnode头指针节点,将newVnode尾指针对应的DOM插入到oldVnode头指针对应的DOM之前,oldCh头指针向前移一位,newCh尾指针向后退一位。

    vue+diff+最全讲解 5、newVnode不包含oldVnode头指针节点,将oldVnode头指针对应的DOM删除,newCh头指针向前移一位,oldCh尾指针向后退一位。

    vue+diff+最全讲解

    6、oldVnode不包含newVnode头指针节点,将newVnode头指针节点插入到oldVnode头指针对应的DOM之前,newCh头指针向前移一位。

    vue+diff+最全讲解

    7、newVnode已经没了,oldVnode剩余的节点4、6、7说明都被删除了,删除对应dom即可。

    vue+diff+最全讲解

    8、最终,DOM完全更新为与newNode一样的结构,diff过程完毕!

    参考文献

    1、www.jianshu.com/p/081103a62…

    2、juejin.cn/post/684490…

    3、www.jianshu.com/p/211c7f216…


    下载网 » vue+diff+最全讲解

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元