深入理解虚拟DOM以及diff算法

1.什么是虚拟DOM

  用JS来模拟DOM结构,将DOM的变化放在JS层来做。换而言之,vdom就是JS对象

2.基本过程

  1. 用 JS 对象模拟 DOM 树
  2. 比较两颗虚拟DOM树的差异–diff算法
  3. 将两个虚拟DOM对象的差异应用到真正的DOM树

3.虚拟DOM真的能提升性能吗?

  使用虚拟 DOM,在DOM 阶段操作少了通讯的确是变高效了,但代价是在 JS 阶段需要完成额外的工作(diff计算),这项额外的工作是需要耗时的!
  虚拟DOM并不是说比原生DOM API的操作快,而是说不管数据怎么变化,都可以以最小的代价来进行更新 DOM。在每个点上,其实用手工的原生方法会比diff好很多。
  框架的意义在于掩盖底层的 DOM 操作,用更声明式的方式来描述,从而让代码更容易维护。

4.diff算法

  1. 首先判断新老节点类型是否相同。如果类型不同,直接用新节点替换老节点;如果类型相同,比较二者的文本,用新节点的文本替换老节点的文本。调用方法updateProperties更新新老节点之间的属性。
  2. 比较儿子。三种情况第一种老的有儿子,新的有儿子(最复杂);第二种老的有儿子,新的没儿子;第三种情况老的没儿子,新的新增了儿子。对于第二种情况直接将节点里面的内容置空即可(domElement.innerHTML = ’ ')。对于第三种情况,将儿子追加到老节点下面即可。最复杂的第一种情况在下面讨论。
  3. 第一种情况:为每个儿子节点(无论新儿子还是老儿子)添加StartIndex(开始索引),StartVnode(开始节点),EndIndex(尾索引),EndVnode(尾节点)。然后就是:
      比较头部(oldStartVnode, newStartVnode)。相同的话StartVnode 和StartIndex都要往后移位。
      比较尾部(oldEndVnode, newEndVnode)。相同的话EndVnode和EndIndex都要前移。
      新节点头和老节点尾比较(oldStartVnode, newEndVnode)。相同的话oldEndVnode添加到oldStartVnode前面。 oldEndVnode和oldEndIndex前移,newStartVnode和newStartIndex后移。
      新节点尾和老节点头比较(oldEndVnode, newStartVnode)。相同的话oldStartVnode插入到oldEndVnode后面。
      如果前面四种都不满足,暴力对比,根据key去老节点查找,如果没有找到就把新节点插入到老节点之前;如果找到了就可以复用,先对比属性,然后把它插入到老节点之前。同时把它变为undefined。无论是否找到,都要移动新节点的开始索引。最后如果老节点里面还有节点(没有设为undefined),直接删除即可。

5.key的作用

  在 vnode 不带 key 的情况下,每一轮的 diff 过程当中都是起始和结束节点进行比较(头和头,尾和尾,头和尾),直到 oldChildren 或者newChildren 被遍历完。而当为 vnode 引入 key 属性后,在每一轮的 diff 过程中,当起始和结束节点都没有找到相同节点(sameVnode) 时,然后再判断在 newStartVnode 的属性中是否有 key,而且在oldChildren找含key的节点。如果不存在,那么就将这个 newStartVnode作为新的节点创建且插入到原有的 root 的子节点中;如果存在这个 key,那么就取出 oldChildren中的存在这个key的vnode,进行复用。

6.diff如何将复杂度简化到o(n^3)

  首先 DOM 是一个多叉树的结构,如果需要完整的对比两颗树的差异,那么需要的时间复杂度会是 O(n ^ 3),这个复杂度肯定是不能接受的。于是 React 团队优化了算法,实现了 O(n) 的复杂度来对比差异。 实现 O(n) 复杂度的关键就是只对比同层的节点,而不是跨层对比,这也是考虑到在实际业务中很少会去跨层的移动 DOM 元素。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值