面试官问: 如何理解Virtual DOM?

261 阅读7分钟

一、vdom是什么? vdom是虚拟DOM(Virtual DOM)的简称,指的是用JS模拟的DOM结构,将DOM变化的对比放在JS层来做。换而言之,vdom就是JS对象。 如下DOM结构:

  • Item1
  • Item2
复制代码映射成虚拟DOM就是这样: { tag: "ul", attrs: { id: "list" }, children: [ { tag: "li", attrs: { className: "item" }, children: ["Item1"] }, { tag: "li", attrs: { className: "item" }, children: ["Item2"] } ] } 复制代码二、为什么要用vdom? 现在有一个场景,实现以下需求: [ { name: "张三", age: "20", address: "北京" }, { name: "李四", age: "21", address: "武汉" }, { name: "王五", age: "22", address: "杭州" }, ] 复制代码将该数据展示成一个表格,并且随便修改一个信息,表格也跟着修改。 用jQuery实现如下: Document
改变

复制代码这样点击按钮,会有相应的视图变化,但是你审查以下元素,每次改动之后,table标签都得重新创建,也就是说table下面的每一个栏目,不管是数据是否和原来一样,都得重新渲染,这并不是理想中的情况,当其中的一栏数据和原来一样,我们希望这一栏不要重新渲染,因为DOM重绘相当消耗浏览器性能。 因此我们采用JS对象模拟的方法,将DOM的比对操作放在JS层,减少浏览器不必要的重绘,提高效率。 当然有人说虚拟DOM并不比真实的DOM快,其实也是有道理的。当上述table中的每一条数据都改变时,显然真实的DOM操作更快,因为虚拟DOM还存在js中diff算法的比对过程。所以,上述性能优势仅仅适用于大量数据的渲染并且改变的数据只是一小部分的情况。 虚拟DOM更加优秀的地方在于: 1、它打开了函数式的UI编程的大门,即UI = f(data)这种构建UI的方式。 2、可以将JS对象渲染到浏览器DOM以外的环境中,也就是支持了跨平台开发,比如ReactNative。 另外大家可以参考尤大的一些回答: www.zhihu.com/question/31… 三、使用snabbdom实现vdom snabbdom地址:github.com/snabbdom/sn… 这是一个简易的实现vdom功能的库,相比vue、react,对于vdom这块更加简易,适合我们学习vdom。vdom里面有两个核心的api,一个是h函数,一个是patch函数,前者用来生成vdom对象,后者的功能在于做虚拟dom的比对和将vdom挂载到真实DOM上。 简单介绍一下这两个函数的用法:

h('标签名', {属性}, [子元素]) h('标签名', {属性}, [文本]) patch(container, vnode) container为容器DOM元素 patch(vnode, newVnode)

现在我们就来用snabbdom重写一下刚才的例子:

Document
改变 复制代码再进入页面:

你会发现,只有改变的栏目才闪烁,也就是进行重绘,数据没有改变的栏目还是保持原样,这样就大大节省了浏览器重新渲染的开销。 四、diff算法 1、什么是diff算法? 所谓diff算法,就是用来找出两段文本之间的差异的一种算法。 作为一个前端,大家经常会听到diff算法这个词,其实diff并不是前端原创的算法,其实这一个算法早已在linux的diff命令中有所体现,并且大家常用的git diff也是运用的diff算法。 2、vdom为什么用diff算法 DOM操作是非常昂贵的,因此我们需要尽量地减少DOM操作。这就需要找出本次DOM必须更新的节点来更新,其他的不更新,这个找出的过程,就需要应用diff算法。 3、vdom中diff算法的简易实现 以下代码只是帮助大家理解diff算法的原理和流程,不可用于生产环境。 将vdom转化为真实dom: const createElement = (vnode) => { let tag = vnode.tag; let attrs = vnode.attrs || {}; let children = vnode.children || []; if(!tag) { return null; } //创建元素 let elem = document.createElement(tag); //属性 let attrName; for (attrName in attrs) { if(attrs.hasOwnProperty(attrName)) { elem.setAttribute(attrName, attrs[attrName]); } } //子元素 children.forEach(childVnode => { //给elem添加子元素 elem.appendChild(createElement(childVnode)); })

//返回真实的dom元素 return elem; } 复制代码用简易diff算法做更新操作: function updateChildren(vnode, newVnode) { let children = vnode.children || []; let newChildren = newVnode.children || [];

children.forEach((childVnode, index) => { let newChildVNode = newChildren[index]; if(childVnode.tag === newChildVNode.tag) { //深层次对比, 递归过程 updateChildren(childVnode, newChildVNode); } else { //替换 replaceNode(childVnode, newChildVNode); } }) } 复制代码参考资料: 知乎尤雨溪回答 揭秘一线互联网企业 前端JavaScript高级面试 前端进阶与面试指南 关注下面的标签,发现更多相似文章JavaScript神三元前端工程师发布了 18 篇专栏 · 获得点赞 1,717 · 获得阅读 46,599关注安装掘金浏览器插件打开新标签页发现好内容,掘金、GitHub、Dribbble、ProductHunt 等站点内容轻松获取。快来安装掘金浏览器插件获取高质量内容吧!评论凉云全栈工程师这个简称不咋简单啊(◔.̮◔)1天前  · 删除 回复凉云全栈工程师 回复 凉云: 教程sorry1天前  · 删除 回复lookjoe前着 => 前者2天前  · 删除 1 回复神三元(作者)前端工程师 回复 lookjoe: 谢谢指出2天前  · 删除 回复A金理学replaceNode(childVnode, newChildVNode);怎么不说下呢?怎么替换啊?2天前  · 删除 回复神三元(作者)前端工程师 回复 A金理学: 直接值替换,知道这个流程就可以2天前  · 删除 回复ZuopieziChen这个不错3天前  · 删除 1 回复CasT1R前端工程师虚拟dom最大的优势是解决了跨平台3天前  · 删除 2 回复神三元(作者)前端工程师 回复 CasT1R: 有人说是函数式,有人说是跨平台。3天前  · 删除 回复ZuopieziChen 回复 CasT1R: 这个倒是真的3天前  · 删除 回复加载更多exciting面试官:虚拟dom是什么? 我:虚拟dom就是用js对象去模拟dom,通过算法对比去更新部分dom,节省性能。 面试官:这个算法是怎样做对比的? 我:...我没有深入研究过。

哈哈! 3天前  · 删除 4 回复神三元(作者)前端工程师 回复 exciting: 把最下面那个函数写给他看就行了3天前  · 删除 回复查看更多 >相关推荐阴明1小时前架构前端JavaScriptFigma 团队分享其插件系统的架构设计3微博微信扫一扫专栏lhyt1天前JavaScript面试官: 你为什么这么强,什么都敢盘(reduce)167微博微信扫一扫专栏聪明的汤姆1天前JavaScript这些Web API真的有用吗? 别问,问就是有用🈶41683微博微信扫一扫专栏nanfeiyan1天前JavaScriptenv 文件与环境设置9微博微信扫一扫专栏前端小智2天前JavaScriptECMAScript 65个 JS 解构有趣的用途12814微博微信扫一扫专栏lhyt5天前JavaScriptthree.js一步步带你实现web全景看房——three.js46834微博微信扫一扫专栏橘子先生吃西瓜1天前JavaScript前端从一次开发联调的问题复盘,理解「规则即自由」73微博微信扫一扫专栏江三疯3天前JavaScript前端前端代码规范 — JavaScript 风格指南1498微博微信扫一扫专栏云中桥5天前JavaScript前端「面试必考」从多线程到Event Loop全面梳理49361微博微信扫一扫专栏_呜啦啦啦火车笛6天前JavaScript前端深入 JavaScript 设计模式,从此有了优化代码的理论依据62437微博微信扫一扫关于作者神三元前端工程师 获得点赞1,717 文章被阅读46,599掘金小册MySQL 是怎样运行的:从根儿上理解 MySQL新人价 ¥14.95¥29.9从入门到深入:IM聊天系统前端开发实践新人价 ¥9.95¥19.9新人专享好礼送你45元买小册立即领取下载掘金客户端一个帮助开发者成长的社区相关文章从头开始,彻底理解服务端渲染原理(8千字汇总长文)69170react hooks+redux+immutable.js打造网易云音乐精美webApp33182面试官问: 如何理解Virtual DOM?12320基于"发布-订阅"的原生JS插件封装16726实现一个简单的Webpack11016目录一、vdom是什么?二、为什么要用vdom?三、使用snabbdom实现vdom四、diff算法1、什么是diff算法?2、vdom为什么用diff算法3、vdom中diff算法的简易实现分享掘金浏览器插件 -