当前位置: 首页 > Web前端 > vue.js

VirtualDOM浅析

时间:2023-03-31 23:00:29 vue.js

Part1什么是VirtualDOMVirtualDOM是对DOM的抽象,本质上是一个JavaScript对象。这个对象是对DOM更轻量级的描述。例如:可以定义一个JS对象结构,它有一个tagName、props、children三个属性,用来表示一个DOM元素的标签名、属性键值对、一级子元素,如如下图所示。在VirtualDOM流行之初,社区中的解决方案往往不是过于臃肿和低效,而是包含的功能过于有限。因此,后来有人开发了著名的虚拟DOM库:Snabbdom.js,具有高性能和体积小的优点https://github.com/snabbdom/s...VUE框架中的虚拟DOM也是一个参考Snabbdom.js的实现Part2为什么需要VirtualDOM一开始,面对后端接口返回的数据,需要写类似下图的代码来操作DOM:我们需要关心数据是哪个DOM绑定到以及如何操作它更改DOM。以上三行代码只是改变一个DOM。如果业务复杂,需要在数据变化时更新多个DOM的视图交互,将不同的数据和操作DOM的逻辑写在一起。这时候代码就会变得繁琐难维护。.因此,为了更好的处理程序的复杂性,后来人们基于职责分离的思想对其进行了分层。一般来说分为Model层(数据模型层)、View层(视图层)和中间的逻辑层。逻辑层负责将数据更新到视图,并在视图与响应交互时反馈给数据层。目前主流的前端框架也是这样做的。我们期望只关心数据的逻辑(也就是Model层),复杂的更新逻辑在框架内部处理,这样当数据发生变化时,绑定到它的DOM可以自动更新,而我们主要维护数据层面的代码就可以了。比如在使用VUE框架时,data中的数据可以看做是Model层。我们只需要关心如何处理数据。当数据改变时,视图会自动更新。无需处理获取DOM等基本操作。这就需要对框架内的逻辑层有一个完善的解决方案。如何在数据变化时更新视图?通过innerHTML替换父元素中内容的暴力方案存在一个问题:每次更新数据,都需要重新构建和渲染整个页面,开销很大:考虑一个DOM元素依赖多个的场景数据源,如果多个数据同时改变,DOM元素也会改变多次,造成多次渲染重绘,每次DOM操作的成本极高。高改进:由于改变一个js对象的成本极低,引入虚拟DOM作为缓冲层,最终将确定的改变一次性更新到真实DOM中。虚拟DOM的优点是抽象了DOM并缓冲了变化。需要全局视图更新的场景具有性能优势,便于数据驱动管理。你可以在操作DOM之前做更多可能的操作。第三部分Snabbdom.js分析Snabbdom中的核心对象VNode,Snabbdom中DOM的抽象Module和Hook,Snabbdom中的模块和hook的目录结构Snabbdom的执行机制Snabbdom的执行机制patch方法启动diff比较。比较原则:只比较同一水平。如果两个vnode相同,即sel相同,key相同,则认为这两个vnode值得继续比较,patchVnode(oldVnode,newVnode,...)操作将被执行;如果两个vnode不同,则直接进行DOM替换,省去了子vnode的比较,提高了效率。patchVnode的函数patchVnode(oldVnode:VNode,vnode:VNode,insertedVnodeQueue:VNodeQueue){}updateChildren做了什么Part4VirtualDOM真的很快吗?原生DOM操作与通过框架封装操作这是性能与可维护性之间的权衡。框架的意义就是为你掩盖底层的DOM操作,让你以更声明的方式描述你的目的,从而让你的代码更容易维护。没有框架能比纯手工优化的DOM操作更快,因为框架的DOM操作层需要处理上层API可能产生的任何操作,它的实现必须是通用的。对于任何基准测试,我都可以编写比任何框架都更快的手动优化,但这有什么意义呢?在构建实际应用的时候,是否每个地方都进行手动优化?出于可维护性的原因,这显然是不可能的。框架给你的保证是,我在不手动优化的情况下,依然可以给你提供不错的性能。——摘自尤雨熙关于VirtualDOM性能的回答。如果没有VirtualDOM,简单的思路就是直接resetinnerHTML。但是,在所有数据都发生变化的大列表的情况下,重新设置innerHTML其实是一个合理的操作。但真正的问题在于,在“re-renderall”的思路下,即使只有一行数据改变,也需要重新设置整个innerHTML,这时候显然有很多浪费。InnerHTMLvs.VirtualDOM重绘性能消耗:innerHTML:renderhtmlstringO(templatesize)+recreateallDOMO(DOMsize)VirtualDOM:rendervirtualDOM+diffO(templatesize)+necessaryDOMupdateO(DOMchange)渲染虚拟DOM+diff明显比渲染html字符串要慢一些,但仍然是纯js层面的计算,比后面的DOM操作还是便宜不少。可以看出,innerHTML的总计算量,无论是js计算还是DOM操作,都与整个界面的大小有关,而在VirtualDOM的计算量中,只有js计算与界面大小有关,而DOM操作与数据变化相关。.这就是为什么要有VirtualDOM的原因:它保证了①无论你的数据变化多少,每次重绘的性能都是可以接受的;②你仍然可以用类似于innerHTML的思路来编写你的应用程序。——摘自游雨溪的回答性能比较也要看场合。在比较性能时,需要区分初始渲染、少量数据更新和大量数据更新。VirtualDOM的真正价值从来都不是性能,而是它①打开了函数式UI编程的大门②可以渲染到DOM以外的后端,比如ReactNative。——摘自尤于熙的回答