一、真实DOM与虚拟DOM的本质概念
1.1 真实DOM的定义与结构
真实DOM是浏览器原生提供的文档对象模型,它是HTML或XML文档在内存中的对象表示。当浏览器解析HTML时,会构建出一棵由节点组成的树形结构,每个节点都是DOM对象,包含标签名、属性、子节点、文本内容等信息。
真实DOM的核心特点如下:
一个真实DOM节点的简化创建过程如下:
const div = document.createElement('div');
div.id = 'app';
div.className = 'container';
div.textContent = 'Hello World';
上述代码创建的div对象在浏览器中包含上百个属性和方法,如childNodes、parentNode、style、addEventListener等,这些都是浏览器为每个DOM节点提供的标准接口。
1.2 虚拟DOM的定义与结构
虚拟DOM是用普通JavaScript对象来描述真实DOM的一种轻量级数据结构。它本质上是一棵普通的JavaScript对象树,通过属性来描述DOM节点的标签、类型、属性和子节点,而不是真正的浏览器DOM节点。
虚拟DOM的核心特点如下:
一个虚拟DOM节点的简化结构如下:
{
tag: 'div',
props: {
id: 'app',
className: 'container'
},
children: [
{
tag: 'span',
props: {},
children: ['Hello World']
}
]
}
在React中,虚拟DOM通过createElement函数创建:
const element = React.createElement(
'div',
{ id: 'app', className: 'container' },
React.createElement('span', null, 'Hello World')
);
1.3 两者的核心关系
虚拟DOM与真实DOM并非对立关系,而是协作关系。虚拟DOM是真实DOM在JavaScript层的抽象映射,最终仍需转换为真实DOM才能在页面上呈现。它们的关系可以用如下流程描述:
#publish-mermaid-1785720872674-0{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#publish-mermaid-1785720872674-0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720872674-0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720872674-0 .error-icon{fill:#552222;}#publish-mermaid-1785720872674-0 .error-text{fill:#552222;stroke:#552222;}#publish-mermaid-1785720872674-0 .edge-thickness-normal{stroke-width:1px;}#publish-mermaid-1785720872674-0 .edge-thickness-thick{stroke-width:3.5px;}#publish-mermaid-1785720872674-0 .edge-pattern-solid{stroke-dasharray:0;}#publish-mermaid-1785720872674-0 .edge-thickness-invisible{stroke-width:0;fill:none;}#publish-mermaid-1785720872674-0 .edge-pattern-dashed{stroke-dasharray:3;}#publish-mermaid-1785720872674-0 .edge-pattern-dotted{stroke-dasharray:2;}#publish-mermaid-1785720872674-0 .marker{fill:#333333;stroke:#333333;}#publish-mermaid-1785720872674-0 .marker.cross{stroke:#333333;}#publish-mermaid-1785720872674-0 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#publish-mermaid-1785720872674-0 p{margin:0;}#publish-mermaid-1785720872674-0 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#publish-mermaid-1785720872674-0 .cluster-label text{fill:#333;}#publish-mermaid-1785720872674-0 .cluster-label span{color:#333;}#publish-mermaid-1785720872674-0 .cluster-label span p{background-color:transparent;}#publish-mermaid-1785720872674-0 .label text,#publish-mermaid-1785720872674-0 span{fill:#333;color:#333;}#publish-mermaid-1785720872674-0 .node rect,#publish-mermaid-1785720872674-0 .node circle,#publish-mermaid-1785720872674-0 .node ellipse,#publish-mermaid-1785720872674-0 .node polygon,#publish-mermaid-1785720872674-0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720872674-0 .rough-node .label text,#publish-mermaid-1785720872674-0 .node .label text,#publish-mermaid-1785720872674-0 .image-shape .label,#publish-mermaid-1785720872674-0 .icon-shape .label{text-anchor:middle;}#publish-mermaid-1785720872674-0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#publish-mermaid-1785720872674-0 .rough-node .label,#publish-mermaid-1785720872674-0 .node .label,#publish-mermaid-1785720872674-0 .image-shape .label,#publish-mermaid-1785720872674-0 .icon-shape .label{text-align:center;}#publish-mermaid-1785720872674-0 .node.clickable{cursor:pointer;}#publish-mermaid-1785720872674-0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#publish-mermaid-1785720872674-0 .arrowheadPath{fill:#333333;}#publish-mermaid-1785720872674-0 .edgePath .path{stroke:#333333;stroke-width:1px;}#publish-mermaid-1785720872674-0 .flowchart-link{stroke:#333333;fill:none;}#publish-mermaid-1785720872674-0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720872674-0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#publish-mermaid-1785720872674-0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720872674-0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#publish-mermaid-1785720872674-0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#publish-mermaid-1785720872674-0 .cluster text{fill:#333;}#publish-mermaid-1785720872674-0 .cluster span{color:#333;}#publish-mermaid-1785720872674-0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#publish-mermaid-1785720872674-0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#publish-mermaid-1785720872674-0 rect.text{fill:none;stroke-width:0;}#publish-mermaid-1785720872674-0 .icon-shape,#publish-mermaid-1785720872674-0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720872674-0 .icon-shape p,#publish-mermaid-1785720872674-0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#publish-mermaid-1785720872674-0 .icon-shape .label rect,#publish-mermaid-1785720872674-0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720872674-0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#publish-mermaid-1785720872674-0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#publish-mermaid-1785720872674-0 .node .neo-node{stroke:#9370DB;}#publish-mermaid-1785720872674-0 [data-look=\”neo\”].node rect,#publish-mermaid-1785720872674-0 [data-look=\”neo\”].cluster rect,#publish-mermaid-1785720872674-0 [data-look=\”neo\”].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720872674-0 [data-look=\”neo\”].swimlane.cluster rect{filter:none;}#publish-mermaid-1785720872674-0 [data-look=\”neo\”].node path{stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720872674-0 [data-look=\”neo\”].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720872674-0 [data-look=\”neo\”].node .neo-line path{stroke:#9370DB;filter:none;}#publish-mermaid-1785720872674-0 [data-look=\”neo\”].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720872674-0 [data-look=\”neo\”].node circle .state-start{fill:#000000;}#publish-mermaid-1785720872674-0 [data-look=\”neo\”].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720872674-0 [data-look=\”neo\”].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720872674-0 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
数据状态变更
生成新的虚拟DOM树
与旧虚拟DOM树进行Diff比对
计算出最小变更集合
批量更新真实DOM
页面重新渲染
从流程图可以看出,虚拟DOM充当了数据与真实DOM之间的中间层,通过最小化真实DOM操作来提升性能。
二、真实DOM与虚拟DOM的区别详解
2.1 渲染流程对比
真实DOM的渲染流程相对直接:开发者通过原生API操作DOM,浏览器立即响应并触发重排或重绘。每次操作都会引发浏览器的渲染流程,缺乏批量处理的机制。
真实DOM渲染流程如下:
#publish-mermaid-1785720872861-1{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#publish-mermaid-1785720872861-1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720872861-1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720872861-1 .error-icon{fill:#552222;}#publish-mermaid-1785720872861-1 .error-text{fill:#552222;stroke:#552222;}#publish-mermaid-1785720872861-1 .edge-thickness-normal{stroke-width:1px;}#publish-mermaid-1785720872861-1 .edge-thickness-thick{stroke-width:3.5px;}#publish-mermaid-1785720872861-1 .edge-pattern-solid{stroke-dasharray:0;}#publish-mermaid-1785720872861-1 .edge-thickness-invisible{stroke-width:0;fill:none;}#publish-mermaid-1785720872861-1 .edge-pattern-dashed{stroke-dasharray:3;}#publish-mermaid-1785720872861-1 .edge-pattern-dotted{stroke-dasharray:2;}#publish-mermaid-1785720872861-1 .marker{fill:#333333;stroke:#333333;}#publish-mermaid-1785720872861-1 .marker.cross{stroke:#333333;}#publish-mermaid-1785720872861-1 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#publish-mermaid-1785720872861-1 p{margin:0;}#publish-mermaid-1785720872861-1 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#publish-mermaid-1785720872861-1 .cluster-label text{fill:#333;}#publish-mermaid-1785720872861-1 .cluster-label span{color:#333;}#publish-mermaid-1785720872861-1 .cluster-label span p{background-color:transparent;}#publish-mermaid-1785720872861-1 .label text,#publish-mermaid-1785720872861-1 span{fill:#333;color:#333;}#publish-mermaid-1785720872861-1 .node rect,#publish-mermaid-1785720872861-1 .node circle,#publish-mermaid-1785720872861-1 .node ellipse,#publish-mermaid-1785720872861-1 .node polygon,#publish-mermaid-1785720872861-1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720872861-1 .rough-node .label text,#publish-mermaid-1785720872861-1 .node .label text,#publish-mermaid-1785720872861-1 .image-shape .label,#publish-mermaid-1785720872861-1 .icon-shape .label{text-anchor:middle;}#publish-mermaid-1785720872861-1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#publish-mermaid-1785720872861-1 .rough-node .label,#publish-mermaid-1785720872861-1 .node .label,#publish-mermaid-1785720872861-1 .image-shape .label,#publish-mermaid-1785720872861-1 .icon-shape .label{text-align:center;}#publish-mermaid-1785720872861-1 .node.clickable{cursor:pointer;}#publish-mermaid-1785720872861-1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#publish-mermaid-1785720872861-1 .arrowheadPath{fill:#333333;}#publish-mermaid-1785720872861-1 .edgePath .path{stroke:#333333;stroke-width:1px;}#publish-mermaid-1785720872861-1 .flowchart-link{stroke:#333333;fill:none;}#publish-mermaid-1785720872861-1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720872861-1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#publish-mermaid-1785720872861-1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720872861-1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#publish-mermaid-1785720872861-1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#publish-mermaid-1785720872861-1 .cluster text{fill:#333;}#publish-mermaid-1785720872861-1 .cluster span{color:#333;}#publish-mermaid-1785720872861-1 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#publish-mermaid-1785720872861-1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#publish-mermaid-1785720872861-1 rect.text{fill:none;stroke-width:0;}#publish-mermaid-1785720872861-1 .icon-shape,#publish-mermaid-1785720872861-1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720872861-1 .icon-shape p,#publish-mermaid-1785720872861-1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#publish-mermaid-1785720872861-1 .icon-shape .label rect,#publish-mermaid-1785720872861-1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720872861-1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#publish-mermaid-1785720872861-1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#publish-mermaid-1785720872861-1 .node .neo-node{stroke:#9370DB;}#publish-mermaid-1785720872861-1 [data-look=\”neo\”].node rect,#publish-mermaid-1785720872861-1 [data-look=\”neo\”].cluster rect,#publish-mermaid-1785720872861-1 [data-look=\”neo\”].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720872861-1 [data-look=\”neo\”].swimlane.cluster rect{filter:none;}#publish-mermaid-1785720872861-1 [data-look=\”neo\”].node path{stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720872861-1 [data-look=\”neo\”].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720872861-1 [data-look=\”neo\”].node .neo-line path{stroke:#9370DB;filter:none;}#publish-mermaid-1785720872861-1 [data-look=\”neo\”].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720872861-1 [data-look=\”neo\”].node circle .state-start{fill:#000000;}#publish-mermaid-1785720872861-1 [data-look=\”neo\”].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720872861-1 [data-look=\”neo\”].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720872861-1 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
JavaScript操作DOM API
浏览器立即解析
触发重排Reflow
触发重绘Repaint
页面更新
等待下一次操作
虚拟DOM的渲染流程则引入了中间层:数据变化先反映在虚拟DOM上,通过Diff算法计算出差异,再将差异批量应用到真实DOM。这种方式将多次DOM操作合并为一次,显著减少了浏览器的重排重绘次数。
虚拟DOM渲染流程如下:
#publish-mermaid-1785720872942-2{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#publish-mermaid-1785720872942-2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720872942-2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720872942-2 .error-icon{fill:#552222;}#publish-mermaid-1785720872942-2 .error-text{fill:#552222;stroke:#552222;}#publish-mermaid-1785720872942-2 .edge-thickness-normal{stroke-width:1px;}#publish-mermaid-1785720872942-2 .edge-thickness-thick{stroke-width:3.5px;}#publish-mermaid-1785720872942-2 .edge-pattern-solid{stroke-dasharray:0;}#publish-mermaid-1785720872942-2 .edge-thickness-invisible{stroke-width:0;fill:none;}#publish-mermaid-1785720872942-2 .edge-pattern-dashed{stroke-dasharray:3;}#publish-mermaid-1785720872942-2 .edge-pattern-dotted{stroke-dasharray:2;}#publish-mermaid-1785720872942-2 .marker{fill:#333333;stroke:#333333;}#publish-mermaid-1785720872942-2 .marker.cross{stroke:#333333;}#publish-mermaid-1785720872942-2 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#publish-mermaid-1785720872942-2 p{margin:0;}#publish-mermaid-1785720872942-2 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#publish-mermaid-1785720872942-2 .cluster-label text{fill:#333;}#publish-mermaid-1785720872942-2 .cluster-label span{color:#333;}#publish-mermaid-1785720872942-2 .cluster-label span p{background-color:transparent;}#publish-mermaid-1785720872942-2 .label text,#publish-mermaid-1785720872942-2 span{fill:#333;color:#333;}#publish-mermaid-1785720872942-2 .node rect,#publish-mermaid-1785720872942-2 .node circle,#publish-mermaid-1785720872942-2 .node ellipse,#publish-mermaid-1785720872942-2 .node polygon,#publish-mermaid-1785720872942-2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720872942-2 .rough-node .label text,#publish-mermaid-1785720872942-2 .node .label text,#publish-mermaid-1785720872942-2 .image-shape .label,#publish-mermaid-1785720872942-2 .icon-shape .label{text-anchor:middle;}#publish-mermaid-1785720872942-2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#publish-mermaid-1785720872942-2 .rough-node .label,#publish-mermaid-1785720872942-2 .node .label,#publish-mermaid-1785720872942-2 .image-shape .label,#publish-mermaid-1785720872942-2 .icon-shape .label{text-align:center;}#publish-mermaid-1785720872942-2 .node.clickable{cursor:pointer;}#publish-mermaid-1785720872942-2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#publish-mermaid-1785720872942-2 .arrowheadPath{fill:#333333;}#publish-mermaid-1785720872942-2 .edgePath .path{stroke:#333333;stroke-width:1px;}#publish-mermaid-1785720872942-2 .flowchart-link{stroke:#333333;fill:none;}#publish-mermaid-1785720872942-2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720872942-2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#publish-mermaid-1785720872942-2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720872942-2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#publish-mermaid-1785720872942-2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#publish-mermaid-1785720872942-2 .cluster text{fill:#333;}#publish-mermaid-1785720872942-2 .cluster span{color:#333;}#publish-mermaid-1785720872942-2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#publish-mermaid-1785720872942-2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#publish-mermaid-1785720872942-2 rect.text{fill:none;stroke-width:0;}#publish-mermaid-1785720872942-2 .icon-shape,#publish-mermaid-1785720872942-2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720872942-2 .icon-shape p,#publish-mermaid-1785720872942-2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#publish-mermaid-1785720872942-2 .icon-shape .label rect,#publish-mermaid-1785720872942-2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720872942-2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#publish-mermaid-1785720872942-2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#publish-mermaid-1785720872942-2 .node .neo-node{stroke:#9370DB;}#publish-mermaid-1785720872942-2 [data-look=\”neo\”].node rect,#publish-mermaid-1785720872942-2 [data-look=\”neo\”].cluster rect,#publish-mermaid-1785720872942-2 [data-look=\”neo\”].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720872942-2 [data-look=\”neo\”].swimlane.cluster rect{filter:none;}#publish-mermaid-1785720872942-2 [data-look=\”neo\”].node path{stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720872942-2 [data-look=\”neo\”].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720872942-2 [data-look=\”neo\”].node .neo-line path{stroke:#9370DB;filter:none;}#publish-mermaid-1785720872942-2 [data-look=\”neo\”].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720872942-2 [data-look=\”neo\”].node circle .state-start{fill:#000000;}#publish-mermaid-1785720872942-2 [data-look=\”neo\”].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720872942-2 [data-look=\”neo\”].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720872942-2 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
数据状态变更
生成新虚拟DOM树
Diff算法比对
计算最小变更集
批量更新真实DOM
一次性重排重绘
页面更新
两者的关键区别在于:真实DOM是同步的、即时的操作,而虚拟DOM是异步的、批量的操作。
2.2 性能开销对比
真实DOM的性能开销主要体现在两个方面:
虚拟DOM的性能优势体现在:
但虚拟DOM并非在所有场景下都更快。对于单次简单DOM操作,直接操作真实DOM反而比经过虚拟DOM的中转更高效。虚拟DOM的优势体现在频繁、复杂的UI更新场景。
性能对比示意如下:
| 操作类型 | 真实DOM | 虚拟DOM |
|———|———|———|
| 单次简单操作 | 快 | 略慢(多一层中转) |
| 大量频繁更新 | 慢(频繁重排) | 快(批量更新) |
| 首次渲染 | 快 | 略慢(需构建虚拟树) |
| 复杂列表更新 | 慢 | 快(配合Key优化) |
2.3 跨平台能力对比
真实DOM强依赖浏览器环境,无法在Node.js或其他非浏览器环境中运行。这导致服务端渲染(SSR)等场景下,直接操作DOM会报错。
虚拟DOM因为是纯JavaScript对象,具有天然的跨平台能力:
跨平台工作原理如下:
#publish-mermaid-1785720873011-3{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#publish-mermaid-1785720873011-3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720873011-3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720873011-3 .error-icon{fill:#552222;}#publish-mermaid-1785720873011-3 .error-text{fill:#552222;stroke:#552222;}#publish-mermaid-1785720873011-3 .edge-thickness-normal{stroke-width:1px;}#publish-mermaid-1785720873011-3 .edge-thickness-thick{stroke-width:3.5px;}#publish-mermaid-1785720873011-3 .edge-pattern-solid{stroke-dasharray:0;}#publish-mermaid-1785720873011-3 .edge-thickness-invisible{stroke-width:0;fill:none;}#publish-mermaid-1785720873011-3 .edge-pattern-dashed{stroke-dasharray:3;}#publish-mermaid-1785720873011-3 .edge-pattern-dotted{stroke-dasharray:2;}#publish-mermaid-1785720873011-3 .marker{fill:#333333;stroke:#333333;}#publish-mermaid-1785720873011-3 .marker.cross{stroke:#333333;}#publish-mermaid-1785720873011-3 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#publish-mermaid-1785720873011-3 p{margin:0;}#publish-mermaid-1785720873011-3 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#publish-mermaid-1785720873011-3 .cluster-label text{fill:#333;}#publish-mermaid-1785720873011-3 .cluster-label span{color:#333;}#publish-mermaid-1785720873011-3 .cluster-label span p{background-color:transparent;}#publish-mermaid-1785720873011-3 .label text,#publish-mermaid-1785720873011-3 span{fill:#333;color:#333;}#publish-mermaid-1785720873011-3 .node rect,#publish-mermaid-1785720873011-3 .node circle,#publish-mermaid-1785720873011-3 .node ellipse,#publish-mermaid-1785720873011-3 .node polygon,#publish-mermaid-1785720873011-3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720873011-3 .rough-node .label text,#publish-mermaid-1785720873011-3 .node .label text,#publish-mermaid-1785720873011-3 .image-shape .label,#publish-mermaid-1785720873011-3 .icon-shape .label{text-anchor:middle;}#publish-mermaid-1785720873011-3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#publish-mermaid-1785720873011-3 .rough-node .label,#publish-mermaid-1785720873011-3 .node .label,#publish-mermaid-1785720873011-3 .image-shape .label,#publish-mermaid-1785720873011-3 .icon-shape .label{text-align:center;}#publish-mermaid-1785720873011-3 .node.clickable{cursor:pointer;}#publish-mermaid-1785720873011-3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#publish-mermaid-1785720873011-3 .arrowheadPath{fill:#333333;}#publish-mermaid-1785720873011-3 .edgePath .path{stroke:#333333;stroke-width:1px;}#publish-mermaid-1785720873011-3 .flowchart-link{stroke:#333333;fill:none;}#publish-mermaid-1785720873011-3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720873011-3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#publish-mermaid-1785720873011-3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720873011-3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#publish-mermaid-1785720873011-3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#publish-mermaid-1785720873011-3 .cluster text{fill:#333;}#publish-mermaid-1785720873011-3 .cluster span{color:#333;}#publish-mermaid-1785720873011-3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#publish-mermaid-1785720873011-3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#publish-mermaid-1785720873011-3 rect.text{fill:none;stroke-width:0;}#publish-mermaid-1785720873011-3 .icon-shape,#publish-mermaid-1785720873011-3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720873011-3 .icon-shape p,#publish-mermaid-1785720873011-3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#publish-mermaid-1785720873011-3 .icon-shape .label rect,#publish-mermaid-1785720873011-3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720873011-3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#publish-mermaid-1785720873011-3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#publish-mermaid-1785720873011-3 .node .neo-node{stroke:#9370DB;}#publish-mermaid-1785720873011-3 [data-look=\”neo\”].node rect,#publish-mermaid-1785720873011-3 [data-look=\”neo\”].cluster rect,#publish-mermaid-1785720873011-3 [data-look=\”neo\”].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873011-3 [data-look=\”neo\”].swimlane.cluster rect{filter:none;}#publish-mermaid-1785720873011-3 [data-look=\”neo\”].node path{stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720873011-3 [data-look=\”neo\”].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873011-3 [data-look=\”neo\”].node .neo-line path{stroke:#9370DB;filter:none;}#publish-mermaid-1785720873011-3 [data-look=\”neo\”].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873011-3 [data-look=\”neo\”].node circle .state-start{fill:#000000;}#publish-mermaid-1785720873011-3 [data-look=\”neo\”].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873011-3 [data-look=\”neo\”].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873011-3 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}浏览器服务端移动端桌面端
虚拟DOM树
目标平台
ReactDOM渲染为真实DOM
ReactDOMServer渲染为HTML字符串
ReactNative渲染为原生组件
ReactNativeWindows渲染为原生控件
这种跨平台能力是虚拟DOM最重要的优势之一,也是React等框架能够支撑多端开发的基础。
三、真实DOM的优缺点分析
3.1 真实DOM的优点
真实DOM作为浏览器原生标准,具有以下优点:
3.2 真实DOM的缺点
真实DOM的主要缺点集中在性能和开发体验上:
一个典型的性能问题示例如下:
// 真实DOM: 1000次操作触发1000次重排
for (let i = 0; i < 1000; i++) {
const li = document.createElement('li');
li.textContent = `Item ${i}`;
document.getElementById('list').appendChild(li);
}
上述代码每次appendChild都会触发一次重排,1000次循环将导致严重的性能问题。
3.3 真实DOM的适用场景
真实DOM适合以下场景:
四、虚拟DOM的优缺点分析
4.1 虚拟DOM的优点
虚拟DOM作为现代前端框架的核心技术,优势显著:
批量更新示例如下:
// 虚拟DOM: 1000次状态变更只触发一次重排
function App() {
const [items, setItems] = useState([]);
useEffect(() => {
const newItems = [];
for (let i = 0; i < 1000; i++) {
newItems.push(`Item ${i}`);
}
setItems(newItems); // 一次性更新
}, []);
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}
上述代码中,1000个列表项的更新通过虚拟DOM的批量机制,最终只触发一次DOM操作。
4.2 虚拟DOM的缺点
虚拟DOM并非完美,也存在以下不足:
虚拟DOM的性能边界如下:
#publish-mermaid-1785720873084-4{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#publish-mermaid-1785720873084-4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720873084-4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720873084-4 .error-icon{fill:#552222;}#publish-mermaid-1785720873084-4 .error-text{fill:#552222;stroke:#552222;}#publish-mermaid-1785720873084-4 .edge-thickness-normal{stroke-width:1px;}#publish-mermaid-1785720873084-4 .edge-thickness-thick{stroke-width:3.5px;}#publish-mermaid-1785720873084-4 .edge-pattern-solid{stroke-dasharray:0;}#publish-mermaid-1785720873084-4 .edge-thickness-invisible{stroke-width:0;fill:none;}#publish-mermaid-1785720873084-4 .edge-pattern-dashed{stroke-dasharray:3;}#publish-mermaid-1785720873084-4 .edge-pattern-dotted{stroke-dasharray:2;}#publish-mermaid-1785720873084-4 .marker{fill:#333333;stroke:#333333;}#publish-mermaid-1785720873084-4 .marker.cross{stroke:#333333;}#publish-mermaid-1785720873084-4 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#publish-mermaid-1785720873084-4 p{margin:0;}#publish-mermaid-1785720873084-4 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#publish-mermaid-1785720873084-4 .cluster-label text{fill:#333;}#publish-mermaid-1785720873084-4 .cluster-label span{color:#333;}#publish-mermaid-1785720873084-4 .cluster-label span p{background-color:transparent;}#publish-mermaid-1785720873084-4 .label text,#publish-mermaid-1785720873084-4 span{fill:#333;color:#333;}#publish-mermaid-1785720873084-4 .node rect,#publish-mermaid-1785720873084-4 .node circle,#publish-mermaid-1785720873084-4 .node ellipse,#publish-mermaid-1785720873084-4 .node polygon,#publish-mermaid-1785720873084-4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720873084-4 .rough-node .label text,#publish-mermaid-1785720873084-4 .node .label text,#publish-mermaid-1785720873084-4 .image-shape .label,#publish-mermaid-1785720873084-4 .icon-shape .label{text-anchor:middle;}#publish-mermaid-1785720873084-4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#publish-mermaid-1785720873084-4 .rough-node .label,#publish-mermaid-1785720873084-4 .node .label,#publish-mermaid-1785720873084-4 .image-shape .label,#publish-mermaid-1785720873084-4 .icon-shape .label{text-align:center;}#publish-mermaid-1785720873084-4 .node.clickable{cursor:pointer;}#publish-mermaid-1785720873084-4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#publish-mermaid-1785720873084-4 .arrowheadPath{fill:#333333;}#publish-mermaid-1785720873084-4 .edgePath .path{stroke:#333333;stroke-width:1px;}#publish-mermaid-1785720873084-4 .flowchart-link{stroke:#333333;fill:none;}#publish-mermaid-1785720873084-4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720873084-4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#publish-mermaid-1785720873084-4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720873084-4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#publish-mermaid-1785720873084-4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#publish-mermaid-1785720873084-4 .cluster text{fill:#333;}#publish-mermaid-1785720873084-4 .cluster span{color:#333;}#publish-mermaid-1785720873084-4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#publish-mermaid-1785720873084-4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#publish-mermaid-1785720873084-4 rect.text{fill:none;stroke-width:0;}#publish-mermaid-1785720873084-4 .icon-shape,#publish-mermaid-1785720873084-4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720873084-4 .icon-shape p,#publish-mermaid-1785720873084-4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#publish-mermaid-1785720873084-4 .icon-shape .label rect,#publish-mermaid-1785720873084-4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720873084-4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#publish-mermaid-1785720873084-4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#publish-mermaid-1785720873084-4 .node .neo-node{stroke:#9370DB;}#publish-mermaid-1785720873084-4 [data-look=\”neo\”].node rect,#publish-mermaid-1785720873084-4 [data-look=\”neo\”].cluster rect,#publish-mermaid-1785720873084-4 [data-look=\”neo\”].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873084-4 [data-look=\”neo\”].swimlane.cluster rect{filter:none;}#publish-mermaid-1785720873084-4 [data-look=\”neo\”].node path{stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720873084-4 [data-look=\”neo\”].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873084-4 [data-look=\”neo\”].node .neo-line path{stroke:#9370DB;filter:none;}#publish-mermaid-1785720873084-4 [data-look=\”neo\”].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873084-4 [data-look=\”neo\”].node circle .state-start{fill:#000000;}#publish-mermaid-1785720873084-4 [data-look=\”neo\”].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873084-4 [data-look=\”neo\”].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873084-4 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}简单操作复杂频繁更新
操作复杂度
是否值得使用虚拟DOM
直接操作真实DOM更快
虚拟DOM批量更新更优
虚拟DOM反而增加开销
虚拟DOM优势明显
4.3 虚拟DOM的适用场景
虚拟DOM适合以下场景:
五、虚拟DOM的Diff算法与更新机制
5.1 Diff算法核心思想
Diff算法是虚拟DOM性能优化的核心,其目标是高效地比较新旧两棵虚拟DOM树,找出最小变更集合。由于完整的树Diff时间复杂度为O(n^3),在实际应用中不可接受,因此React等框架采用了启发式策略,将复杂度降为O(n)。
Diff算法的三大假设如下:
Diff流程如下:
#publish-mermaid-1785720873139-5{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#publish-mermaid-1785720873139-5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720873139-5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720873139-5 .error-icon{fill:#552222;}#publish-mermaid-1785720873139-5 .error-text{fill:#552222;stroke:#552222;}#publish-mermaid-1785720873139-5 .edge-thickness-normal{stroke-width:1px;}#publish-mermaid-1785720873139-5 .edge-thickness-thick{stroke-width:3.5px;}#publish-mermaid-1785720873139-5 .edge-pattern-solid{stroke-dasharray:0;}#publish-mermaid-1785720873139-5 .edge-thickness-invisible{stroke-width:0;fill:none;}#publish-mermaid-1785720873139-5 .edge-pattern-dashed{stroke-dasharray:3;}#publish-mermaid-1785720873139-5 .edge-pattern-dotted{stroke-dasharray:2;}#publish-mermaid-1785720873139-5 .marker{fill:#333333;stroke:#333333;}#publish-mermaid-1785720873139-5 .marker.cross{stroke:#333333;}#publish-mermaid-1785720873139-5 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#publish-mermaid-1785720873139-5 p{margin:0;}#publish-mermaid-1785720873139-5 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#publish-mermaid-1785720873139-5 .cluster-label text{fill:#333;}#publish-mermaid-1785720873139-5 .cluster-label span{color:#333;}#publish-mermaid-1785720873139-5 .cluster-label span p{background-color:transparent;}#publish-mermaid-1785720873139-5 .label text,#publish-mermaid-1785720873139-5 span{fill:#333;color:#333;}#publish-mermaid-1785720873139-5 .node rect,#publish-mermaid-1785720873139-5 .node circle,#publish-mermaid-1785720873139-5 .node ellipse,#publish-mermaid-1785720873139-5 .node polygon,#publish-mermaid-1785720873139-5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720873139-5 .rough-node .label text,#publish-mermaid-1785720873139-5 .node .label text,#publish-mermaid-1785720873139-5 .image-shape .label,#publish-mermaid-1785720873139-5 .icon-shape .label{text-anchor:middle;}#publish-mermaid-1785720873139-5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#publish-mermaid-1785720873139-5 .rough-node .label,#publish-mermaid-1785720873139-5 .node .label,#publish-mermaid-1785720873139-5 .image-shape .label,#publish-mermaid-1785720873139-5 .icon-shape .label{text-align:center;}#publish-mermaid-1785720873139-5 .node.clickable{cursor:pointer;}#publish-mermaid-1785720873139-5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#publish-mermaid-1785720873139-5 .arrowheadPath{fill:#333333;}#publish-mermaid-1785720873139-5 .edgePath .path{stroke:#333333;stroke-width:1px;}#publish-mermaid-1785720873139-5 .flowchart-link{stroke:#333333;fill:none;}#publish-mermaid-1785720873139-5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720873139-5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#publish-mermaid-1785720873139-5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720873139-5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#publish-mermaid-1785720873139-5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#publish-mermaid-1785720873139-5 .cluster text{fill:#333;}#publish-mermaid-1785720873139-5 .cluster span{color:#333;}#publish-mermaid-1785720873139-5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#publish-mermaid-1785720873139-5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#publish-mermaid-1785720873139-5 rect.text{fill:none;stroke-width:0;}#publish-mermaid-1785720873139-5 .icon-shape,#publish-mermaid-1785720873139-5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720873139-5 .icon-shape p,#publish-mermaid-1785720873139-5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#publish-mermaid-1785720873139-5 .icon-shape .label rect,#publish-mermaid-1785720873139-5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720873139-5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#publish-mermaid-1785720873139-5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#publish-mermaid-1785720873139-5 .node .neo-node{stroke:#9370DB;}#publish-mermaid-1785720873139-5 [data-look=\”neo\”].node rect,#publish-mermaid-1785720873139-5 [data-look=\”neo\”].cluster rect,#publish-mermaid-1785720873139-5 [data-look=\”neo\”].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873139-5 [data-look=\”neo\”].swimlane.cluster rect{filter:none;}#publish-mermaid-1785720873139-5 [data-look=\”neo\”].node path{stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720873139-5 [data-look=\”neo\”].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873139-5 [data-look=\”neo\”].node .neo-line path{stroke:#9370DB;filter:none;}#publish-mermaid-1785720873139-5 [data-look=\”neo\”].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873139-5 [data-look=\”neo\”].node circle .state-start{fill:#000000;}#publish-mermaid-1785720873139-5 [data-look=\”neo\”].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873139-5 [data-look=\”neo\”].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873139-5 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}相同不同有Key无Key
新旧虚拟DOM树
同层节点比较
节点类型是否相同
更新属性
替换整个节点
递归比较子节点
销毁旧节点及子树
是否有Key
按Key匹配复用
按索引顺序比较
输出变更集合
批量更新真实DOM
5.2 同层比较策略
同层比较是Diff算法最重要的优化策略。它假设DOM的跨层级移动很少发生,因此只比较同一层级的节点。如果发现某节点在新树中消失了,不会去其他层级查找,而是直接销毁。
同层比较示例:
// 旧树
{
tag: 'div',
children: [
{ tag: 'p', children: ['Hello'] }
]
}
// 新树
{
tag: 'div',
children: [
{ tag: 'span', children: ['Hello'] }
]
}
在上述示例中,Diff算法发现p变成了span,类型不同,直接销毁p节点及其子树,创建新的span节点。即使两者的文本内容相同,也不会复用。
5.3 Key的作用与原理
Key是虚拟DOM Diff算法中识别节点的关键标识。在列表渲染时,Key帮助算法准确判断哪些节点是新增、删除或移动的,从而最大化节点复用,减少不必要的创建和销毁。
Key的工作原理如下:
#publish-mermaid-1785720873243-6{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#publish-mermaid-1785720873243-6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720873243-6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720873243-6 .error-icon{fill:#552222;}#publish-mermaid-1785720873243-6 .error-text{fill:#552222;stroke:#552222;}#publish-mermaid-1785720873243-6 .edge-thickness-normal{stroke-width:1px;}#publish-mermaid-1785720873243-6 .edge-thickness-thick{stroke-width:3.5px;}#publish-mermaid-1785720873243-6 .edge-pattern-solid{stroke-dasharray:0;}#publish-mermaid-1785720873243-6 .edge-thickness-invisible{stroke-width:0;fill:none;}#publish-mermaid-1785720873243-6 .edge-pattern-dashed{stroke-dasharray:3;}#publish-mermaid-1785720873243-6 .edge-pattern-dotted{stroke-dasharray:2;}#publish-mermaid-1785720873243-6 .marker{fill:#333333;stroke:#333333;}#publish-mermaid-1785720873243-6 .marker.cross{stroke:#333333;}#publish-mermaid-1785720873243-6 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#publish-mermaid-1785720873243-6 p{margin:0;}#publish-mermaid-1785720873243-6 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#publish-mermaid-1785720873243-6 .cluster-label text{fill:#333;}#publish-mermaid-1785720873243-6 .cluster-label span{color:#333;}#publish-mermaid-1785720873243-6 .cluster-label span p{background-color:transparent;}#publish-mermaid-1785720873243-6 .label text,#publish-mermaid-1785720873243-6 span{fill:#333;color:#333;}#publish-mermaid-1785720873243-6 .node rect,#publish-mermaid-1785720873243-6 .node circle,#publish-mermaid-1785720873243-6 .node ellipse,#publish-mermaid-1785720873243-6 .node polygon,#publish-mermaid-1785720873243-6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720873243-6 .rough-node .label text,#publish-mermaid-1785720873243-6 .node .label text,#publish-mermaid-1785720873243-6 .image-shape .label,#publish-mermaid-1785720873243-6 .icon-shape .label{text-anchor:middle;}#publish-mermaid-1785720873243-6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#publish-mermaid-1785720873243-6 .rough-node .label,#publish-mermaid-1785720873243-6 .node .label,#publish-mermaid-1785720873243-6 .image-shape .label,#publish-mermaid-1785720873243-6 .icon-shape .label{text-align:center;}#publish-mermaid-1785720873243-6 .node.clickable{cursor:pointer;}#publish-mermaid-1785720873243-6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#publish-mermaid-1785720873243-6 .arrowheadPath{fill:#333333;}#publish-mermaid-1785720873243-6 .edgePath .path{stroke:#333333;stroke-width:1px;}#publish-mermaid-1785720873243-6 .flowchart-link{stroke:#333333;fill:none;}#publish-mermaid-1785720873243-6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720873243-6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#publish-mermaid-1785720873243-6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720873243-6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#publish-mermaid-1785720873243-6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#publish-mermaid-1785720873243-6 .cluster text{fill:#333;}#publish-mermaid-1785720873243-6 .cluster span{color:#333;}#publish-mermaid-1785720873243-6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#publish-mermaid-1785720873243-6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#publish-mermaid-1785720873243-6 rect.text{fill:none;stroke-width:0;}#publish-mermaid-1785720873243-6 .icon-shape,#publish-mermaid-1785720873243-6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720873243-6 .icon-shape p,#publish-mermaid-1785720873243-6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#publish-mermaid-1785720873243-6 .icon-shape .label rect,#publish-mermaid-1785720873243-6 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720873243-6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#publish-mermaid-1785720873243-6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#publish-mermaid-1785720873243-6 .node .neo-node{stroke:#9370DB;}#publish-mermaid-1785720873243-6 [data-look=\”neo\”].node rect,#publish-mermaid-1785720873243-6 [data-look=\”neo\”].cluster rect,#publish-mermaid-1785720873243-6 [data-look=\”neo\”].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873243-6 [data-look=\”neo\”].swimlane.cluster rect{filter:none;}#publish-mermaid-1785720873243-6 [data-look=\”neo\”].node path{stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720873243-6 [data-look=\”neo\”].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873243-6 [data-look=\”neo\”].node .neo-line path{stroke:#9370DB;filter:none;}#publish-mermaid-1785720873243-6 [data-look=\”neo\”].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873243-6 [data-look=\”neo\”].node circle .state-start{fill:#000000;}#publish-mermaid-1785720873243-6 [data-look=\”neo\”].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873243-6 [data-look=\”neo\”].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873243-6 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
旧列表: A B C D
新列表: B A D E
按Key匹配
A: 位置从0变1
B: 位置从1变0
C: 不存在删除
D: 位置不变
E: 新增
移动A
移动B
删除C
创建E
Key的使用原则如下:
正确使用Key的示例:
// 正确: 使用唯一ID作为Key
{items.map(item => (
<li key={item.id}>{item.name}</li>
))}
// 错误: 使用索引作为Key
{items.map((item, index) => (
<li key={index}>{item.name}</li>
))}
六、实际开发中的选择建议
6.1 何时选择真实DOM
在以下情况下,直接操作真实DOM更为合适:
6.2 何时选择虚拟DOM
在以下情况下,使用虚拟DOM(通过React、Vue等框架)更为合适:
6.3 综合对比总结
真实DOM与虚拟DOM的综合对比如下:
#publish-mermaid-1785720873325-7{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#publish-mermaid-1785720873325-7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720873325-7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#publish-mermaid-1785720873325-7 .error-icon{fill:#552222;}#publish-mermaid-1785720873325-7 .error-text{fill:#552222;stroke:#552222;}#publish-mermaid-1785720873325-7 .edge-thickness-normal{stroke-width:1px;}#publish-mermaid-1785720873325-7 .edge-thickness-thick{stroke-width:3.5px;}#publish-mermaid-1785720873325-7 .edge-pattern-solid{stroke-dasharray:0;}#publish-mermaid-1785720873325-7 .edge-thickness-invisible{stroke-width:0;fill:none;}#publish-mermaid-1785720873325-7 .edge-pattern-dashed{stroke-dasharray:3;}#publish-mermaid-1785720873325-7 .edge-pattern-dotted{stroke-dasharray:2;}#publish-mermaid-1785720873325-7 .marker{fill:#333333;stroke:#333333;}#publish-mermaid-1785720873325-7 .marker.cross{stroke:#333333;}#publish-mermaid-1785720873325-7 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#publish-mermaid-1785720873325-7 p{margin:0;}#publish-mermaid-1785720873325-7 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#publish-mermaid-1785720873325-7 .cluster-label text{fill:#333;}#publish-mermaid-1785720873325-7 .cluster-label span{color:#333;}#publish-mermaid-1785720873325-7 .cluster-label span p{background-color:transparent;}#publish-mermaid-1785720873325-7 .label text,#publish-mermaid-1785720873325-7 span{fill:#333;color:#333;}#publish-mermaid-1785720873325-7 .node rect,#publish-mermaid-1785720873325-7 .node circle,#publish-mermaid-1785720873325-7 .node ellipse,#publish-mermaid-1785720873325-7 .node polygon,#publish-mermaid-1785720873325-7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720873325-7 .rough-node .label text,#publish-mermaid-1785720873325-7 .node .label text,#publish-mermaid-1785720873325-7 .image-shape .label,#publish-mermaid-1785720873325-7 .icon-shape .label{text-anchor:middle;}#publish-mermaid-1785720873325-7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#publish-mermaid-1785720873325-7 .rough-node .label,#publish-mermaid-1785720873325-7 .node .label,#publish-mermaid-1785720873325-7 .image-shape .label,#publish-mermaid-1785720873325-7 .icon-shape .label{text-align:center;}#publish-mermaid-1785720873325-7 .node.clickable{cursor:pointer;}#publish-mermaid-1785720873325-7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#publish-mermaid-1785720873325-7 .arrowheadPath{fill:#333333;}#publish-mermaid-1785720873325-7 .edgePath .path{stroke:#333333;stroke-width:1px;}#publish-mermaid-1785720873325-7 .flowchart-link{stroke:#333333;fill:none;}#publish-mermaid-1785720873325-7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720873325-7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#publish-mermaid-1785720873325-7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720873325-7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#publish-mermaid-1785720873325-7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#publish-mermaid-1785720873325-7 .cluster text{fill:#333;}#publish-mermaid-1785720873325-7 .cluster span{color:#333;}#publish-mermaid-1785720873325-7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#publish-mermaid-1785720873325-7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#publish-mermaid-1785720873325-7 rect.text{fill:none;stroke-width:0;}#publish-mermaid-1785720873325-7 .icon-shape,#publish-mermaid-1785720873325-7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785720873325-7 .icon-shape p,#publish-mermaid-1785720873325-7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#publish-mermaid-1785720873325-7 .icon-shape .label rect,#publish-mermaid-1785720873325-7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785720873325-7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#publish-mermaid-1785720873325-7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#publish-mermaid-1785720873325-7 .node .neo-node{stroke:#9370DB;}#publish-mermaid-1785720873325-7 [data-look=\”neo\”].node rect,#publish-mermaid-1785720873325-7 [data-look=\”neo\”].cluster rect,#publish-mermaid-1785720873325-7 [data-look=\”neo\”].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873325-7 [data-look=\”neo\”].swimlane.cluster rect{filter:none;}#publish-mermaid-1785720873325-7 [data-look=\”neo\”].node path{stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785720873325-7 [data-look=\”neo\”].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873325-7 [data-look=\”neo\”].node .neo-line path{stroke:#9370DB;filter:none;}#publish-mermaid-1785720873325-7 [data-look=\”neo\”].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873325-7 [data-look=\”neo\”].node circle .state-start{fill:#000000;}#publish-mermaid-1785720873325-7 [data-look=\”neo\”].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873325-7 [data-look=\”neo\”].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785720873325-7 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
真实DOM vs 虚拟DOM
真实DOM
虚拟DOM
优点: 直接高效标准统一
缺点: 频繁操作性能差跨平台受限
适合: 简单页面原生开发
优点: 批量优化跨平台声明式
缺点: 首次渲染慢内存占用调试复杂
适合: 复杂应用跨平台数据驱动
核心对比表如下:
| 维度 | 真实DOM | 虚拟DOM |
|—–|———|———|
| 本质 | 浏览器原生对象 | JavaScript对象 |
| 创建成本 | 高 | 低 |
| 操作方式 | 命令式 | 声明式 |
| 性能(频繁更新) | 差 | 优 |
| 性能(单次操作) | 优 | 略差 |
| 跨平台 | 不支持 | 支持 |
| 状态管理 | 手动 | 自动 |
| 学习成本 | 低 | 中 |
| 适用规模 | 小型 | 中大型 |
总结来说,真实DOM是浏览器的基础设施,虚拟DOM是在其之上的抽象层与优化策略。两者并非替代关系,而是互补关系。在现代前端开发中,虚拟DOM通过Diff算法和批量更新机制,有效解决了真实DOM频繁操作的性能问题,同时带来了跨平台和声明式开发的优势。理解两者的区别与优缺点,有助于开发者在不同场景下做出合理的技术选型,写出高性能、可维护的前端代码。