为什么需要虚拟DOM?

为什么需要虚拟DOM?目录 1 真实 DOM 操作的性能问题 2 虚拟 DOM 的作用总结我们知道 虚拟 DOM 的概念是由 Facebook 的 React 团队最早提出来的 也是 React 框架的核心概念之一 它的作用是以 js 的形式在内存中描述真实的 DOM 结构 这样当页面内容需要发生变动时 React 可以通过对前后虚拟 DOM 的比对 计算出如何以最小的代价操作真实 DOM 1 真实 DOM 操作的性能问题在虚拟 DOM 出现之前 前端开发者最常用的方式是用 jQuery 直接操作真实 DOM 像下面这样 body body

我们知道,虚拟DOM的概念是由Facebook的React团队最早提出来的,也是React框架的核心概念之一。它的作用是以js的形式在内存中描述真实的DOM结构,这样当页面内容需要发生变动时,React可以通过对前后虚拟DOM的比对,计算出如何以最小的代价操作真实DOM。

1. 真实DOM操作的性能问题

在虚拟DOM出现之前,前端开发者最常用的方式是用jQuery直接操作真实DOM,像下面这样:

<body> <div id="root"></div> <script> $('#root').text('这是一段文本'); // 或者这种原生的方式 // var root = document.querySelector('#root'); // root.textContent = '这是一段文本'; </script> </body> 

在本例中,jQuery只是提供了一层对原生DOM操作的封装。我们可以简单手写一个$实现:

function $ (selector) { 
     this.nodeList = document.querySelectorAll(selector); return this; } $.prototype.text = function (textContent) { 
     this.nodeList.forEach(node => { 
     node.textContent = textContent; }); return this; } 

(本例只是用于解释jQuery的封装原理,并非jQuery的真实实现)

通过这个简单的封装我们可以发现,jQuery的主要工作是提供对原生DOM操作的统一实现(另外还有对原生js的增强,如ajax、动画等)。换句话说,使用jQuery,本质上还是在直接操作真实DOM。

那么直接操作真实DOM有什么问题呢?

在深色区域的右侧紧邻着的是JavaScriptCore,即webkit默认的JavaScript引擎(在Chrome和chromium中它被替换为了V8),它负责执行JavaScript代码。

我们知道,JavaScript具备操作DOM树的能力。但是从浏览器内核的结构可以看到,DOM树由DOM模块负责管理,在浏览器内核中单独占有一块内存,而这块内存与JavaScript引擎所管理的内存并无直接关系。换句话说,JavaScript引擎不能直接操作真实DOM树。

为了给JavaScript提供操作DOM树的能力,浏览器在全局对象window上为JavaScript封装了一个document对象,然后在该对象上提供了大量的DOM操作接口,这些接口都是用C++实现的。如:
在这里插入图片描述
在浏览器控制台查看document.getElementById,可以看到它的函数体是{ [native code] },这表示它是一个用C++编写的函数,因此无法查看具体实现。当我们在调用这个函数时,JavaScript引擎并没有直接与DOM模块交互,而是由浏览器来操作DOM模块,随后再把操作结果返回给JavaScript引擎。这种借助父级模块实现两个同级模块交互的通信方式非常常见。




所以,截止到目前,如何有效地减少对真实DOM的操作,仍然是前端性能优化的一个关键点。虚拟DOM就是目前较为流行的一个解决方案。

2. 虚拟DOM的作用

但是虚拟DOM带来了一个重要的优势,那就是我们可以在完全不访问真实DOM的情况下,掌握DOM的结构,这为框架自动优化DOM操作提供了可能。举例来说,如果我们本打算手动进行三次真实DOM操作,而框架在分析了虚拟DOM的结构后,把这三次DOM操作简化成了一次,这不就带来了性能上的提升吗?再甚者,如果连这一次DOM操作都可以由框架自动完成(自动更新的前提是我们要定义视图和数据的绑定关系),而我们只需要负责处理数据,那么虚拟DOM的价值体现得就更明显了。

React就是这么使用虚拟DOM的。

当我们使用jsx语法定义一个模板时,React会用它生成一个由JavaScript描述的虚拟DOM树,并将其保存在JavaScript内存中。这个虚拟DOM树还保留了我们在模板中定义的数据和视图的绑定关系,这为React自动根据数据变化更新视图提供了可能。随后当数据发生变化时,React重新生成一个虚拟DOM树,通过对比两个虚拟DOM树的差异,React就可以知道该如何高效地更新视图。接着它就会调用原生的DOM接口,去更新真实DOM。过程大致如下:
在这里插入图片描述
对于开发者而言,虚拟DOM的实现是透明的,它只是框架自动高效更新DOM的一种内部解决方案。开发者需要按照框架给定的语法定义数据和视图的绑定关系,随后就只需要关心数据变化(即业务逻辑)即可。




当然了,虚拟DOM并不是解决DOM操作性能问题的唯一解决方案,Vue的响应式系统也是一种重要的解决方案。从某种程度上来说,Vue依靠响应式系统可以实现“精确定点更新”,即直接定位到哪个DOM节点需要更新,而不需要经过虚拟DOM的比对,不过“精确定点更新”的内存代价偏大,因此目前Vue采用了响应式系统和虚拟DOM结合的方式,本文暂不详述。

最后我们来看一下Vue中虚拟DOM树的结构,实际上它就是一个js对象而已,我们以下面的模板为例:

<template> <div id="app"> <ul> <li v-for=“item in items”> itemid: { 
    { 
     item.id }} </li> </ul> </div> </template> 

总结

要理解为什么需要虚拟DOM,必须弄清楚JavaScript引擎和DOM模块之间的关系,并体会由这种关系导致的DOM操作的性能问题。虚拟DOM设计的核心就是用高效的js操作,来减少低性能的DOM操作,以此来提升网页性能。

从一定程度上来说,是浏览器的架构问题催生了虚拟DOM,而这个架构问题几乎需要重构浏览器内核才能解决,所以目前虚拟DOM仍广为流行。如果未来的某一天,真实DOM被迁移到JavaScript内存中,虚拟DOM的价值实际上也就不存在了。


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/211211.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午10:57
下一篇 2026年3月18日 下午10:57


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号