JS每日一题:Vue中的diff算法?

20190125

Vue中的diff算法?vue

概念: diff算法是一种优化手段,将先后两个模块进行差别对比,修补(更新)差别的过程叫作patch(打补丁)

为何vue,react这些框架中都会有diff算法呢? 咱们都知道渲染真实dom的开销是很大的,这个跟性能优化中的重绘重排意义相似, 回到正题来, 有时候咱们修改了页面中的某个数据,若是直接渲染到真实DOM中会引发整棵数的重绘重排, 那么咱们能不能只让咱们修改的数据映射到真实DOM, 作一个最少化重绘重排呢,说到这里你应该对为何使用diff算法有一个简单的概念了node

virtual DOM和真实DOM的区别

一句话归纳吧,virtual DOM是将真实的DOM的数据抽取出来,以对象的形式模拟树形结构, diff 算法比较的也是virtual DOMreact

代码理解git

<div>
    <p>JS每日一题</p>
</div>

// 转换成VNode 相似于下面这种

const Vnode = {
    tag: 'div',
    children: [
        { tag: 'p', text: 'JS每日一题' }
    ]
};
diff 是如何比较的?
源码太多了,就不贴了, 有兴趣的能够本身看看 https://github.com/vuejs/vue/...

简单的说就是新旧虚拟dom 的比较,若是有差别就以新的为准,而后再插入的真实的dom中,从新渲染github

特色算法

  • 只会作同级比较,不作跨级比较
  • 比较后几种状况性能优化

    • if (oldVnode === vnode),他们的引用一致,能够认为没有变化。
    • if(oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text),文本节点的比较,须要修改,则会调用Node.textContent = vnode.text
    • if( oldCh && ch && oldCh !== ch ), 两个节点都有子节点,并且它们不同,这样咱们会调用updateChildren函数比较子节点,这是diff的核心
    • else if (ch),只有新的节点有子节点,调用createEle(vnode)vnode.el已经引用了老的dom节点,createEle函数会在老dom节点上添加子节点。
    • else if (oldCh),新节点没有子节点,老节点有子节点,直接删除老节点。
key的做用

设置key和不设置key的区别:
不设key,newCh和oldCh只会进行头尾两端的相互比较,设key后,除了头尾两端的比较外,还会从用key生成的对象oldKeyToIdx中查找匹配的节点,因此为节点设置key能够更高效的利用dom框架

如咱们但愿能够在B和C之间加一个F,Diff算法默认执行起来是这样的:dom

即把C更新成F,D更新成C,E更新成D,最后再插入E,是否是很没有效率?函数

因此咱们须要使用key来给每一个节点作一个惟一标识,Diff算法就能够正确的识别此节点,找到正确的位置区插入新的节点。



因此一句话,key的做用主要是为了高效的更新虚拟DOM。另外vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue能够区分它们,不然vue只会替换其内部属性而不会触发过渡效果

总结

  • 尽可能不要跨层级的修改dom
  • 在开发组件时,保持稳定的 DOM 结构会有助于性能的提高
  • 设置key可让diff更高效

关于JS每日一题

JS每日一题能够当作是一个语音答题社区
天天利用碎片时间采用60秒内的语音形式来完成当天的考题
群主在第二天0点推送当天的参考答案

  • 注 毫不仅限于完成当天任务,更可能是查漏补缺,学习群内其它同窗优秀的答题思路

点击加入答题

相关文章
相关标签/搜索