这 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 直接操作的能力,使得其性能会下降,在类似页面列表渲染种,使用虚拟列表,展示可见部分,或者分页等物理方式进行优化。

相关推荐
陈随易17 分钟前
在 VSCode 里,把项目一键部署到服务器
前端·后端·程序员
Highcharts.js35 分钟前
教程:基于 React + Highcharts 构建一个单页应用程序、按需数据拉取与图表渲染
开发语言·前端·数据结构·react.js·前端框架·highcharts·页面应用
To_OC1 小时前
我被 useState 坑了两次之后,终于把它的脾气摸透了
前端·javascript·react.js
鱼樱前端1 小时前
我用 Claude Code 后,编码效率翻 3 倍。但更值钱的是别的。
前端·后端·ai编程
犀利豆1 小时前
Claude code tools 研究系列-开篇(AskUserQuestion)
后端
_lucas1 小时前
给知识库网站接入AI问答
前端·ai编程·全栈
前端糕手2 小时前
前端面试题大全:JavaScript + Vue3 + React + TypeScript + 工程化 + 性能优化
前端
我不叫武3 小时前
一个用 Rust 写的离线编码查询桌面工具
前端
Web4Browser4 小时前
指纹浏览器 API 自动化怎么接:启动 Profile、获取 CDP 端点并连接自动化框架
前端·网络·typescript·自动化
Patrick_Wilson4 小时前
从 React 到 Flutter:写给前端的一张跨端知识地图
前端·flutter·react.js