这 5 种情况下虚拟 dom 的性能不如原生 dom

虚拟DOM的设计目的是提供一种更高效的方式来构建和更新Web应用程序的用户界面,同时降低了性能开销和提高了开发效率。有时候我们会遇到这个问题,虚拟 dom 性能一定会超过原生 dom?

答案是:不一定。

一、页面初始化渲染

像 React/Vue 这种基于虚拟 dom 的框架,在第一渲染页面的时候,如果页面内容较多,需要虚拟 dom 的运行时计算出实际 dom, 此时还没有涉及到重新渲染复用虚拟 dom, 此时与运行计算时间肯会造成页面的白屏时间。

二、静态内容渲染

  • React 渲染
ts 复制代码
// 引入React
import React from 'react';
import ReactDOM from 'react-dom';

// 一个简单的React组件
const SimplePage = () => (
  <div>
    <h1>Hello, World!</h1>
    <p>This is a simple static page.</p>
  </div>
);

// 渲染React组件到实际DOM
ReactDOM.render(<SimplePage />, document.getElementById('app'));
  • 原生 dom 渲染
ts 复制代码
// 获取实际DOM容器
const container = document.getElementById('app');

// 创建和设置实际DOM元素
const div = document.createElement('div');
const heading = document.createElement('h1');
heading.textContent = 'Hello, World!';
const paragraph = document.createElement('p');
paragraph.textContent = 'This is a simple static page.';

// 将元素添加到容器
div.appendChild(heading);
div.appendChild(paragraph);
container.appendChild(div);

对于页面(组件)中包含了静态内容的时候,使用 React 渲染,需要 React 的运行时计算过程,显然没有原生 dom 直接渲染的性能好。

三、大规模数据更新

tsx 复制代码
const container = document.getElementById('container');

function updateData() {
  const data = Array.from({ length: 1000 }, (_, index) => index);

  const virtualList = data.map((item) => {
    return <li key={item}>{item}</li>;
  });
  ReactDOM.render(<ul>{virtualList}</ul>, container);
}

updateData();


setInterval(() => {
  updateData(); // 模拟每秒更新一次数据
}, 1000);

一个每秒更新一次数据。尽管虚拟DOM通常能够提高性能,但由于每秒更新大量数据,虚拟DOM需要不断创建虚拟DOM元素、比较差异并更新实际DOM,这可能会导致性能下降。这里我们需要了解 React 一些特性来优化:

  • 物理上可以:分页和无限滚动加载,减少一次性加载的数据量。
  • 使用 memo api 来优化重复重复渲染。
  • 渲染可见部分的数据,而不是全部的数据,例如虚拟列表组件
  • 其他的

四、复杂的动画

动画一般都会涉及到元素的重绘和重排,这些操作会导致浏览器重新渲染页面元素。

  • 重绘:在不改变元素的布局的情况下,更新元素的可见样式(颜色、背景)
  • 重排:改变元素的布局,可能导致整个元素的重新布局。

它们都会影响性能的开销,如通过虚拟 dom 进行修改,虚拟 dom 需要额外的自己的与运行时,增加额外的性能。

  • React 渲染
ts 复制代码
import React, { useState } from 'react';

function AnimatedComponent() {
  const [left, setLeft] = useState(0);

  const animateLeft = () => {
    setLeft(left + 10);
  };

  return (
    <div>
      <button onClick={animateLeft}>Animate</button>
      <div
        style={{
          width: '100px',
          height: '100px',
          backgroundColor: 'blue',
          transform: `translateX(${left}px)`,
        }}
      />
    </div>
  );
}

export default AnimatedComponent;
  • 原生 dom 渲染
ts 复制代码
const box = document.getElementById('box');
let left = 0;

document.getElementById('animateButton').addEventListener('click', () => {
  left += 10;
  box.style.transform = `translateX(${left}px)`;
});

React 渲染需要状态配合,计算整个 style 当前值,会影响 dom 的内容,明显此时的性能会稍微有所下降。

五、低级的 dom 控制

直接访问和操作底层DOM元素的情况,而虚拟DOM库通常会将这些细节进行抽象和封装。在这些情况下,直接使用原生DOM操作通常更合适,因为它提供了更大的灵活性。

ts 复制代码
// 获取一个DOM元素
const element = document.getElementById('myElement');

// 直接操作DOM,例如添加一个事件处理程序
element.addEventListener('click', () => {
  element.style.backgroundColor = 'red';
});

// 手动创建新的DOM元素
const newElement = document.createElement('div');
newElement.textContent = 'This is a new element';

// 插入新元素到DOM中
document.body.appendChild(newElement);

// 移除DOM元素
const elementToRemove = document.getElementById('elementToRemove');
if (elementToRemove) {
  elementToRemove.parentNode.removeChild(elementToRemove);
}

此处挂载节点:

  • appendChild 添加到元素到指定 dom 种。
  • 从父接节点 parentNode.removeChild 移除一个元素

六、虚拟 dom 的优势

虚拟 dom 优势在于:

  • 优化、批量处理更新以及减少重排和重绘等性能。
  • 组件化开发
  • 跨平台兼容性
  • 生态系统和社区支持

八、原生 dom 优势

  • 学习曲线
  • 直接控制
  • 适合小型项目
  • 性能优势
  • 定制需求

七、小结

虚拟 dom 自身的优点是适合工程化组件化开发的大型项目,但是存在 运行时, 这些虚拟 dom 一般都有自己的运行时代码,在一些小的 dom 操作时不占据优势,在一些大的项目中虚拟 dom 配合组件化开发的优势得以体现,尽管虚拟 dom 可以优化,但是原生 dom 直接操作的能力,使得其性能会下降,在类似页面列表渲染种,使用虚拟列表,展示可见部分,或者分页等物理方式进行优化。

相关推荐
咖啡の猫1 小时前
Shell脚本-for循环应用案例
前端·chrome
uzong2 小时前
面试官:Redis中的 16 库同时发送命令,服务端是串行执行还是并行执行
后端·面试·架构
百万蹄蹄向前冲3 小时前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
追逐时光者3 小时前
.NET 使用 MethodTimer 进行运行耗时统计提升代码的整洁性与可维护性!
后端·.net
朝阳5814 小时前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路4 小时前
GeoTools 读取影像元数据
前端
ssshooter4 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
你的人类朋友4 小时前
【Node.js】什么是Node.js
javascript·后端·node.js
Jerry5 小时前
Jetpack Compose 中的状态
前端
David爱编程6 小时前
面试必问!线程生命周期与状态转换详解
java·后端