Virtual DOM
就是 虚拟DOM,是用 JS 对象描述 DOM 节点的数据,由 React 团队推广出来的。
虚拟DOM 是前端的网红,因此也有很多开发者开始研究和搞辩论赛。
其实主要对比了使用虚拟DOM和直接操作真实DOM的区别。
在 React 中实现数据驱动视图大概流程是这样的:
数据发生变化 -> 通过diff算法判断要更新哪些节点 -> 找到要更新的节点 -> 更新真实DOM
Vue 的数据更新原理其实也差不多,只是实现方式和使用语法会有所不同。
diff算法 会根据数据更新前和更新后生成的虚拟DOM进行对比,只有两个版本的虚拟DOM存在差异时,才会更新对应的真实DOM。
使用虚拟DOM对比的方式会比直接对比真实DOM的效率高。
而且真实DOM身上挂载的属性和方法非常多,使用虚拟DOM的方式去描述DOM节点树会显得更轻便。
但这也意味着每次数据发生变化时都要先创建一个虚拟DOM,并使用 diff算法 将新虚拟DOM与旧虚拟DOM进行比对,这个步骤会消耗一点性能和需要一点执行时间。
React 和其他虚拟 DOM 框架使用的差异算法很快。可以说,更大的开销在于组件本身。看如下代码:
function StrawManComponent(props) {
const value = expensivelyCalculateValue(props.foo);
return (
<p>the value is {value}</p>
);
}
因为您会value
在每次更新时不小心重新计算,无论是否props.foo
已更改。但是以看起来更良性的方式进行不必要的计算和分配是非常常见的:
function MoreRealisticComponent(props) {
const [selected, setSelected] = useState(null);
return (
<div>
<p>Selected {selected ? selected.name : 'nothing'}</p>
<ul>
{props.items.map(item =>
<li>
<button onClick={() => setSelected(item)}>
{item.name}
</button>
</li>
)}
</ul>
</div>
);
}
在这里,我们正在生成一个新的虚拟<li>
元素数组——每个都有自己的内联事件处理程序——在每次状态更改时,无论是否props.items
已更改。所以虚拟DOM在性能方面的损耗还是比较大的,需要有很高的内存。
而 Svelte 在未使用虚拟DOM的情况下实现了响应式设计。
我以粗暴的方式理解:Svelte 会监听顶层组件所有变量,一旦某个变量发生变化,就更新使用过该变量的组件。这就仅仅只需更新受影响的那部分DOM元素,而不需要整个组件更新。
综上所述,在我的理解力,虚拟DOM的思想很优秀,也是顺应时代的产物,但虚拟DOM并不是最快的,JS 直接操作 DOM 才是最快。