Virtual DOM - the Difference Maker in React JS(译)
原文地址:Virtual DOM - the Difference Maker in React JS
介绍
响应时间是现代网站面临的最大挑战之一,具体来说就是,怎么样使用户快速的访问网页并完成其任务。随着许多UI库的出现,它们所有都试图独立的解决上述问题。在本文中,你将看到React如何使用被称为虚拟DOM的东西来解决这个问题,以及该算法如何使React JS成为众多UI库中的首选。
形象比喻
在开始研究技术细节之前,让我们来对虚拟DOM做个类比。想象一下,一对夫妇去参加聚会,双方都花了大量时间注重细节、精心打扮。当他们离开家并见到最好的朋友时,他迅速给她提建议让她佩戴另外一件不同的珠宝。设想她返回家并从头开始化妆而不是替换珠宝。这就是UI尝试对整个网页进行重新绘制,而不是仅仅替换发生改变的那一部分网页。
什么是虚拟DOM
首先,虚拟DOM不是一个规范,理解这点很重要,它只是与DOM交互的最佳方式。虚拟DOM是使用JavaScript对象来描述HNTML文档。为了与该对象模型交互,每个库都有自己不同的实现方式,来提高网页的渲染和重新渲染的性能。
虚拟DOM vs. 真实DOM
既然更新真实DOM那么慢,那是什么原因使得跟新虚拟DOM这样快的?虚拟DOM不是另外一个DOM对象吗?当然是的。虚拟DOM只是另一个DOM对象,但是它和渲染的网页并不紧密相关。让我们一起看看幕后情况。
您看到的每个网页都有一个与之相等的DOM表示形式,它是一个树形结构,包含所有UI组件。对于UI中状态的任何微小更改,都需要更改其对应的DOM表示,并且需要重新渲染UI。更新DOM本身成本并不高,但是渲染和重新渲染UI使其变得昂贵。考虑到当今我们看到的大多数SPA(单页应用程序)的大小,不是元素的复杂性,而是容纳这些元素的树形结构的大小,这使得渲染UI很费时。
使用虚拟DOM进行优化
在任何时间点,React库都维护两个虚拟DOM。我们将其中一个称为原始版本,将另一个称为脏版本。每当UI中的状态发生变化时,React都会跟踪更改并开始进行批量处理。 这些更改不会应用于实际的DOM,而是会应用于虚拟DOM的脏版本。 在特定的时间(由React确定),它将在原始版本和脏版本之间执行diff操作,并计算增量。 稍后,此增量将应用于实际DOM,以便仅更新网页的所需部分,而不用重新绘制整个网页。
让我们更深入地了解这一解释,看看幕后发生了什么。以下是React渲染算法的一部分关键操作。
高效的diff算法
调用render()方法的任何地方都会创建一个React元素树。如果状态改变,将会再次调用render()方法,它将返回一个不同的React元素树。现在,挑战在于如何有效地更新UI以匹配新生成的树。对于具有“ n”个元素数量的树,复杂度约为O(n3)。 React基于两个假设实现了优化的O(n)算法:
- 不同类型的元素将产生不同的树结构。
如果根元素具有不同的类型,React会将旧的树元素替换为新的树。如果两个React元素具有相同的类型,它将比较属性并仅更新修改后的属性。让我们看一个打印“我爱ReactJS”的简单React组件。如果我们将标记更改为标记,则所有组件标签将被卸载,其状态将被破坏。相反,如果我们只是在其中更改“ className”属性标签,React将保留相同的DOM节点,只会单独更改属性。
class Hello extends React.component {
render() {
return(
<div className="test1">
<Hello />
</div>
)
}
}
function Hello() {
return <h1>I love ReactJS</h1>;
}
- 不同渲染中,使用key属性来找到可能存在稳定结构的子元素。
在生成脏虚拟DOM和原始虚拟DOM之间的差异时,React只是并行地遍历两棵树,并在发现差异时生成突变。因此,如果开发人员可以使用key属性来提示React来标识元素,那么React将使用此键来匹配两棵树之间的元素,并最大程度地减少不必要的变动。
广度优先搜索
React使用广度优先搜索算法遍历DOM树。在该算法中,节点从上到下以及从左到右遍历。 如果React找到任何被修改的元素,默认情况下,它将重新渲染该子树,而无需进一步检查树的深度。
在上面的DOM树示例中,尽管元素B和B11都被修改,但是一旦React发现元素B被修改,它将标记该树并且其下面的子树也被标记。
批量修改操作
我们需要记住,JavaScript是一个单线程模型,将针对DOM树发生的所有事件添加到调用堆栈中,并且事件循环执行添加的调用。关键是,无论在React事件处理程序中对组件调用setState()多少次,它们都将在事件结束时仅产生一次重新渲染。
总结
通过有效地利用上述算法,我们可以肯定地说,React使用虚拟DOM具有几乎完美的UI呈现,过去几年使用React的公司数量以及React框架的使用率的持续增长就是证明。