为何React创建10000条列表项比原生DOM调用更慢?
你观察到的性能差异主要来自以下几个核心原因:
使用了React开发构建版本
你的React代码引入的是react.development.js和react-dom.development.js,这两个版本包含大量调试、警告、错误检查逻辑(比如Props校验、开发日志、严格模式相关代码),这些额外逻辑会大幅增加运行时开销。如果换成生产环境的压缩版本(react.production.min.js和react-dom.production.min.js),React的性能会大幅提升,甚至在很多场景下追平原生DOM。计时逻辑存在致命偏差
你的原生DOM代码中,列表创建的循环是在第一个<script>里同步执行的,而计时的renderStart是在第二个<script>中定义的——这意味着列表创建的耗时根本没被统计到No React的日志里。而React的root.render()是在第一个<script>中调用的,计时逻辑统计的时间包含了React渲染的全部开销,两者的统计范围完全不一致,根本没有可比性。正确的做法应该是把计时逻辑精准包裹在渲染操作前后:比如原生代码把
renderStart放在循环执行前,elapsed放在循环结束后;React代码则可以利用root.render()返回的Promise(React 18支持)来捕获渲染完成的时间,确保统计的是真实的渲染耗时。Virtual DOM的优势不在首次渲染
Virtual DOM的设计初衷是减少频繁更新DOM时的性能损耗,而非优化首次渲染。首次渲染时,React需要先构建Virtual DOM树、完成调和(Reconciliation)流程,再生成真实DOM插入页面,这个过程比直接创建真实DOM多了一层框架逻辑开销。只有当后续需要更新列表(比如修改、删除、添加项)时,Virtual DOM通过对比差异只更新必要的DOM节点,才会体现出显著的性能优势——而原生DOM如果每次更新都要重新操作大量节点,开销会远高于React。现代浏览器对DOM操作的优化
你原本认为原生appendChild会产生数千次DOM往返,但现代浏览器会对同步的DOM操作进行批量优化(比如将多次append合并为一次重排),实际的DOM操作开销并没有你想象的那么大。而React在首次渲染时最终也是生成真实DOM插入,这部分开销和原生相差不大,但加上React自身的框架逻辑开销,就会显得更慢。
内容的提问来源于stack exchange,提问作者Peter Kellner

