这是Svelte的观点:像 React 这样的框架的性能声明只是胡说八道的营销言论,JS UI 框架的价值一般不在于性能,而在于提供“声明性的、状态驱动的 UI 开发”,因为原始 JS/HTML/CSS 开发很糟糕,并且很容易做出糟糕的架构决策和编写无法维护的意大利面条式代码。这样,无论您使用 Vue、React 还是 Angular,它对性能都没有影响。
虚拟 DOM 都会在过程中增加额外的步骤,并且它们有成本。但是它也有用处,从总体上看,如果您手动操作 DOM,那么您很可能只是交换树的整个块,而不是进行外科手术操作。因为手动管理所有这些手术操作很快就会变成一个繁琐的、无法维护的混乱。但是,如果你这样做,你会要求浏览器做更多的重新渲染,这将是代价高昂的。
另外,管理虚拟DOM是有开销的,是的,如果您不按照框架期望的方式构建应用程序,您可能会遇到麻烦。
React 向我们展示了虚拟 DOM 可以为我们提供更好的编程模型并且仍然优于当时基于模板的框架的想法。React 试图争辩说直接 DOM 修改是昂贵的,并且使用虚拟 DOM 会产生更高的性能,这是胡说八道的主张。
React 最初的承诺是,您可以在每次状态更改时重新渲染整个应用程序,而无需担心性能。在实践中,这并不准确。如果是这样,就不需要像这样的优化shouldComponentUpdate(这是告诉 React 何时可以安全地跳过组件的一种方式)。
即使使用shouldComponentUpdate,一次性更新整个应用程序的虚拟 DOM 也需要大量工作。不久前,React 团队引入了一种叫做 React Fiber 的东西,它允许将更新分成更小的块。这意味着(除其他外)更新不会长时间阻塞主线程,尽管它不会减少工作总量或更新所需的时间。
开销从哪里来?
最明显的是,diffing 进行差异区分不是免费的。如果不先将新的虚拟 DOM 与之前的旧快照进行比较,就无法将更改应用于真实 DOM。拿前面的HelloMessage例子来说,假设name道具从“world”变成了“everyone”。
- 两个快照都包含一个元素。在这两种情况下都是 a
,这意味着我们可以保留相同的 DOM 节点
- 我们枚举旧属性
和新属性的所有属性,以查看是否需要更改、添加或删除任何属性。在这两种情况下,我们都有一个属性——aclassName的值为"greeting"
- 下降到这个元素中,我们看到文本发生了变化,因此我们需要更新真实的 DOM
在这三个步骤中,在这种情况下只有第三个步骤有价值,因为 - 与绝大多数更新的情况一样 - 应用程序的基本结构没有改变。如果我们可以直接跳到第 3 步,效率会更高:
if (changed.name) { text.data = name; } |
(这几乎就是 Svelte 生成的更新代码。与传统的 UI 框架不同,Svelte 是一个编译器,它在构建时就知道您的应用程序中的情况如何变化,而不是在运行时等待完成工作。)
组件本身带来开销
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>
);
}
在这里,我们在每次状态更改时生成一个新的虚拟元素
- 数组——每个元素都有自己的内联事件处理程序——无论是否props.items已更改。除非您不健康地痴迷于性能,否则您不会对其进行优化。
-
黑客新闻网友观点
一个 DOM直接修改比一个从虚拟VDOM再到DOM的修改流程要快,当然,如果您经常在每次更新时修改或插入 10,000 个元素,并且不想自己以某种方式批量处理这些元素,那么虚拟VDOM 可能是性能上的胜利。如果数量通常更像是 1-10,则虚拟VDOM可能变成开销负担了。
有一些细微差别。如果您插入读取和写入操作,直接DOM修改仍然很昂贵。声明式范式允许框架批量处理相同类型的操作以防止双重重绘。这是虚拟 DOM与jQuery的好处,但这并不是虚拟 DOM 独有的好处。
虚拟DOM在针头和大海捞针方面有一组不同的权衡:如果相对于一个不是很大DOM有很多修改,那么每个修改变化的虚拟 DOM 开销相对较低。但是,如果您只更新一棵非常大的树中的单个元素,那么每次修改都会产生大量开销。
另一个需要注意的现代混淆因素是一些浏览器(特别是 Chrome)已经做到了,直接通过 DOM API 的修改不再导致重绘阻塞主线程。这意味着任何使用 JS API(而不是DOM API) 来衡量 UI 响应能力的性能基准测试都会有问题。
DOM 也是一种内存数据结构,并且还可以巧妙地将绘制命令批量发送到硬件(GPU 或其他方式)。出于这个原因,我一直对像 React 这样的框架的性能优势持怀疑态度。
UI 框架(React 或 Angular)的最大好处是它将您的代码组织成一个定义的、可维护的模式。传统上,JavaScript 是一门杂乱无章的编程语言,因此使用原始的 JS/HTML 开发很容易让自己陷入困境并做错事。
对我来说,Svelte 最重要的部分是它允许我以最优雅的方式编写 Web 应用程序。编译器优先的方法意味着我们可以选择我们想要的任何语法,使整个过程尽可能愉快。
Svelte 最出色的部分是决定尽可能接近 JavaScript,因此任何了解 JS、HTML 和 CSS 的人都知道 svelte。导入任何 vanilla JS 库都是即插即用的,这意味着社区和生态系统跨越整个 JS 生态系统。不再需要 x-for-react 或 y-for-vue。
看到社区最近呈指数级增长真是太令人兴奋了!!