设计一个虚拟Dom,其实没那么难!
Posted 老陈说前端
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计一个虚拟Dom,其实没那么难!相关的知识,希望对你有一定的参考价值。
老陈发现从17年开始一些响应式的框架就越来越火,之前在读书的时候就觉得这玩意肯定能火,16年就有简单的使用。然后,最近一次小面试问到了如何设计一个虚拟dom,就简单说了是一个dom映射在js对象里面的东西,感觉还是不够深入。所以有了现在这篇文章啦。
假设,我们有一个应用,应用里面有一个数据表,数据表会根据某个字段进行升序或者降序排序展示,这个跟数据库表很像哈,那么我们怎么在页面显示出来呢?
我们设定一个字段名,设定一个升序或者降序的标识,然后通过点击之后,对对象进行排序,再利用js插入页面更新视图。
其实这么做你会发现一个问题,我们要维护的字段特别多,那么点击事件和更新视图的操作就会越来越多。所以我们发现出现了MVC、MVP的架构模式,这只能解决一部分问题,代码组织维护的问题,不能减少操作DOM的次数,该操作还是得操作。
所以那么多的问题,怎么解决呢?我们需要做一个东西,可以让视图和状态绑定,状态变更了视图就自动变更。我们就不需要手动去更新页面。 就是MVVM就呼之欲出了。
只要在模板中声明视图组件是和什么状态进行绑定的,双向绑定引擎就会在状态更新的时候自动更新视图。
他其实解决的是状态维护的问题,大大减少了代码中的视图更新逻辑,但是这不是唯一的办法,还有一个简单粗暴的办法可以大大降低视图更新的操作,一旦状态发生变化,就用模板引擎重新渲染整个视图,替换掉旧的视图,只要用户触发点击事件就更新状态,这样也不需要手动操作DOM了。
innerhtml就完事,这样做就是有一个很不好的弊端,频繁操作DOM,会使性能大大降低,这样的性能成本实在是太高了。
DOM特别慢,记住他,一个div的元素上面就附带着各种各样的属性值,如果你操作可能就会触发页面重排,这就是性能一直被吐槽的原因。
如果是JS的对象,处理起来会更简单,我们可以将DOM树上的结构,属性都用JS表示出来。
let element = {
tagNmae: 'div',
props: {
id: 'items'
},
children: [
{tagName: 'div', props: {class: 'item'}, children: ["Item 1"]},
{tagName: 'div', props: {class: 'item'}, children: ["Item 2"]},
{tagName: 'div', props: {class: 'item'}, children: ["Item 3"]},
]
}
<div id="items">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
</div>
可以仔细看一下上面两个对应关系,我们可以用JS对象表示的树来构建一颗真正的DOM树。
到这,你有没有发现我们都在做无用功,一个JS对象来构建DOM树,重新渲染这个JS对象,该更新还是得更新,搞毛呀。
所以,我们需要对这个树进行一些特殊的操作,就是将新树和旧树进行对比,这样我们到真正对页面进行DOM操作就只会变更需要变更的东西。这一步就是所谓的虚拟DOM算法。
我们可以给虚拟DOM下结论,他其实就是给JS操作和DOM之间加一层,用于对比,虚拟DOM是DOM的一个映射。
比较两个树的差异是虚拟DOM算法最核心的部分,所谓虚拟DOM的两个树之间的diff是一个时间复杂度为O(n^3)的问题,但是在前端,我们只会对同一层进行对比也就是O(n)的时间复杂度。
主要要设计一个虚拟的DOM的话要有三个步骤,第一个是一个DOM到虚拟DOM的映射对象,第二个是diff算法的设计,第三对存在差异的部分进行DOM操作。
看到这里,你应该对虚拟DOM有所了解了,有点标题党了,如果大家有兴趣我在把写好的虚拟DOM部分的源码分享出来。
以上是关于设计一个虚拟Dom,其实没那么难!的主要内容,如果未能解决你的问题,请参考以下文章
堆排序其实没那么难
堆排序其实没那么难
你懂得咋选择彩光模块吗?其实也没那么难!
Linux其实没那么难学
觉得C++难?其实是你没掌握这方法!
看完这篇总结,你会发现其实spring面试真的没那么难,一篇帮你彻底搞定spring。