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

相关推荐
哎呦没10 分钟前
SpringBoot框架下的资产管理自动化
java·spring boot·后端
2401_8576009513 分钟前
SpringBoot框架的企业资产管理自动化
spring boot·后端·自动化
程序员爱技术1 小时前
Vue 2 + JavaScript + vue-count-to 集成案例
前端·javascript·vue.js
并不会2 小时前
常见 CSS 选择器用法
前端·css·学习·html·前端开发·css选择器
衣乌安、2 小时前
【CSS】居中样式
前端·css·css3
兔老大的胡萝卜2 小时前
ppk谈JavaScript,悟透JavaScript,精通CSS高级Web,JavaScript DOM编程艺术,高性能JavaScript pdf
前端·javascript
低代码布道师2 小时前
CSS的三个重点
前端·css
耶啵奶膘4 小时前
uniapp-是否删除
linux·前端·uni-app
NiNg_1_2344 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
王哈哈^_^5 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt