对于这个问题,我想说,如果你找到了比虚拟dom更加好的方案,你当然可以直接使用这么一套方案去植入到框架中,来解决框架的问题。
我认为引入虚拟dom,是因为开发框架的人为了给我们开发者提供更高的开发效率,不需要关心繁琐的dom操作,减少心智负担,提高代码的可维护性等开发出了这么一套框架出来之后,如何操作dom的问题,就转移到了框架那边了。
框架当然可以在每次数据改变之后,把之前渲染的页面全部不要,重新根据我们最新的数据生成一个新的页面,但是,这样做,效率是不是太低了?
仔细想想,我们可以发现,我们是不是可以复用之前页面的那些dom元素呢?
如果这一次渲染出来的页面跟上一次渲染出来的页面,有很多地方都是可以重复应用的,我们完全可以只改动那些真正发生变化的地方。这样一来,问题又变成了我们要如何知道有哪些地方没有变化,哪些地方又真正发生了变化呢?
这时框架开发者们就想出了引入虚拟dom这么一种解决方案
我们先来了解一下虚拟dom是什么:
我们可以理解为,虚拟dom的本质其实就是一个普通的js对象而已,它里面有一些属性,描述了一个真实dom的一些核心的属性和父子结构。如:
const div = {
tag: 'div',
props: {
'id': '#app'
},
children: [{
tag: 'p',
children: 'this is a p'
}]
}
这个div变量保存的对象就可以看作是一个虚拟dom。
在我们了解虚拟dom是什么之后,我们再来看一下框架开发者们是如何将它应用到框架中去的。
框架开发者做出了一套响应式系统后,就有能力给我们开发者提供当数据发生变化时,通知某一些函数重新运行。在框架内部,维护着这么一个流程:
render函数的执行,会返回一个虚拟dom,我们用vnode代替。当数据发生变化,通知我们的render重新运行,运行之后,拿到最新的vnode,也就是描述这次数据变更之后,我们最新的视图长什么样子。然后并没有直接根据这个最新的vnode来操作真实dom来渲染最新的视图,而是将最新的vnode与之前旧的vnode,进行一个对比,找到真正需要更新的地方,再去进行真实的dom操作,从而完成视图的重新渲染。
有了这个一个中间层,相比于之前不管三七二十一直接根据最新的vnode来渲染视图,性能上肯定是提高了不少。
那么现在,为了进一步提高性能,得想出一个办法,怎么样去最快得找出新旧vnode的不同之处呢?也就是找出相对来说性能较高的diff算法。
在vue2中,使用了双端diff,也就是双指针。具体我就不在这里展开了,大家有兴趣可以去了解了解,我之后也会再写一篇文章聊聊
至此,对于为什么需要虚拟dom,我就已经讲完了。对于网上有些争论,说什么虚拟dom效率跟直接操作真实dom效率要高,我觉得是还没有真正理解到位。越接近底层,性能越好,框架是基于原生js实现的,框架也就是在更上层,性能只能说是无限接近原生js,想超越是不可能。
举个例子:有一个页面,点击某个按钮,需要改变某个元素的文本,你觉得使用框架(vnode)来做,跟不使用框架(vnode)来做,哪个效率更高?
先来看看不使用框架,我们只需要在点击的时候,直接操作真实dom的api即可完成效果。
我们再来看看使用框架,对于框架来说,我们不需要关心如何操作dom了,我们只要点击的时候,给与元素的文本绑定的数据重新赋值即可达到效果,可是,框架的渲染是有一套固定的流程的,首先再对数据重新赋值的时候,框架内部通知了render函数相关的watcher,然后调用了watcher函数的update方法,这里面有把render的运行放入了一个微任务队列,同步代码执行完后,将这个微任务取出来执行,也就是执行我们的render函数,这里面各种创建vnode,最终拿到最新的vnode,这还没完,还需要跟旧vnode进行dom diff,最终找到了就是那个元素的文本需要变化,这时调用真正的dom api完成文本的改变。(以上只是描述了一个大概的渲染流程,没有具体展开了)
通过对比,不用我多说了吧,细品...