聊一聊Vue,React都使用的虚拟DOM,是什么。大神们的文章有很多,我也只是做一些总结归纳,提升自己。
虚拟 DOM 是什么
用js模拟一颗dom树,放在浏览器内存中.当你要变更时,虚拟dom使用diff算法进行新旧虚拟dom的比较,将变更放到变更队列中,反应到实际的dom树,减少了dom操作.虚拟DOM将DOM树转换成一个JS对象树,diff算法逐层比较,删除,添加操作,但是,如果有多个相同的元素,可能会浪费性能,所以,react和vue-for引入key值进行区分.
虚拟 DOM 的优点
-
浏览器中GUI渲染线程负责渲染页面,js引擎线程负责解析、执行js代码,如果频繁的操作DOM,那么这两个线程会频繁的切换。如果所操作的
DOM会引发大量的回流或者重绘,这样性能肯定不好 -
如果不使用虚拟
dom,比如现在要操作100次dom,这些操作都会引发回流与重绘,这样浏览器重新渲染100次,并且每一次渲染都是很大的消耗。使用虚拟dom后,因为它是js构造的对象,存在内存中,这100次dom操作都是修改的虚拟dom,是js的计算,修改完毕后,再替换为真实的dom去渲染(渲染1次),而不是渲染100遍。这样减少了浏览器渲染的次数,提高了性能。 -
跨平台: 虚拟
DOM本质上是JavaScript对象,而 DOM 与平台强相关,相比之下虚拟DOM可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。
虚拟 DOM 的缺点
- 无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢。
DOM diff 是什么
就是一个函数,我们称之为 patch
patches = patch(oldVNode, newVNode)
- Tree diff
- 将新旧两棵树逐层对比,找出哪些节点需要更新
- 如果节点是组件就看 Component diff
- 如果节点是标签就看 Element diff
- Component diff
- 如果节点是组件,就先看组件类型
- 类型不同直接替换(删除旧的)
- 类型相同则只更新属性
- 深入组件做 Tree diff(递归)
- Elmenet diff
- 如果节点是原生标签,则看标签名
- 标签名不同直接替换,相同则只更新属性
- 进入标签后代做 Tree diff(递归)
DOM diff 的优点
DOM diff简单来说,就是对比遍历每个节点,然后再操作发生变化的节点。大家都会说DOM diff的有点在于性能高。其实也就是减少了DOM的操作,因为原声DOM会在操作DOM时,进行全量的替换,这对于性能是一种浪费
DOM diff 的问题(key)
- 当计算机对比[1,2,3]与[1,3]时,它是遍历操作,依次对比发现1没变,2变成了3,3被删除了。所以DOM diff就会将输出结果[1,2],所以这时候我们就需要一个
key值,如果我们给每一个值添加一个key值,计算机再去对比时,就会发现1没变,2的id没有了,3没变。DOM diff也会输出正确的值。所以这也就是为什么我们在使用Vue或者React时,都需要添加一个key值,这保证了DOM diff算法的效率。