虚拟DOM为何能解决性能问题

呕吼,前面讲了那么多浏览器怎么去从输入url到页面展示的,现在来讲讲都听过的虚拟DOM吧。

DOM的缺陷

前面讲了DOM树的生成,我相信大家都知道DOM是个嘛玩意儿了(不知道的回头再看看,在点点赞)。

JavaScript的操作DOM也是会影响到渲染流水线的,毕竟DOM改变了,需要从新去计算布局等等。在操纵DOM的时候,如果操纵不当会导致发生强制同步或者布局抖动的问题。

强制同步

强制同步(Forced Synchronous Layout)是指在执行JavaScript代码时,由于需要获取布局信息而导致浏览器强制同步计算布局(也称为重排或回流)。

这种情况通常发生在以下几种情景中:

  1. 读取布局信息:JavaScript代码试图读取一个DOM元素的布局信息(比如宽度、高度、位置等)时,浏览器可能需要立即计算并返回最新的布局信息。这可能导致阻塞,直到布局信息计算完成。
  2. 修改样式: 如果JavaScript代码修改了影响布局的样式属性,例如改变元素的宽度、高度、边距等,浏览器通常会触发重新计算布局。
  3. 获取布局信息后立即修改: 有时候,在获取布局信息后立即修改相应的属性,然后再次读取布局信息,可能会引发强制同步。

强制同步会影响整个渲染流水线,因为浏览器需要停下来重新计算布局,然后重新绘制页面。这可能导致性能问题,特别是在频繁触发强制同步的情况下,页面可能会感觉很卡顿,用户体验下降。

为了避免强制同步,可以采取以下几种优化措施:

  1. 批量修改样式: 尽量将多个样式修改操作放在一起,而不是分散在多个代码段中。这可以减少强制同步的次数。
  2. 使用class进行样式修改: 将样式的修改通过修改元素的class来实现,而不是直接修改元素的style属性。这样可以减少对布局的影响。
  3. 避免频繁读取布局信息: 尽量减少对布局信息的读取操作,或者在必须读取的情况下,尽量将多个读取操作合并为一个。
  4. 使用虚拟DOM: 虚拟DOM是一种在内存中维护的轻量级的DOM表示,通过在虚拟DOM上进行操作,然后一次性将更改应用到实际DOM上,可以最小化强制同步的次数。

布局抖动

布局抖动(Layout Thrashing)是指在网页中频繁执行对DOM元素的读取和写入操作,导致浏览器不断重新计算和渲染页面布局,从而引发性能问题的现象。

这通常发生在JavaScript代码中,特别是在处理多次重复的DOM操作时。 具体来说,布局抖动通常涉及以下几个步骤:

  1. 读取: JavaScript代码读取了某个DOM元素的样式或尺寸。
  2. 写入: JavaScript代码修改了该DOM元素的样式或尺寸,导致页面布局需要重新计算。
  3. 重新布局: 浏览器为了适应新的样式或尺寸,触发了重新计算和绘制页面布局。

如果这个读取和写入的过程在一个循环中不断重复,就会导致频繁的布局抖动,影响网页性能。这样的情况通常可以通过优化JavaScript代码来避免,比如将多次DOM操作合并成一次,或者使用缓存避免重复读取相同的值。

布局抖动是一种常见的性能问题,因为浏览器需要花费大量的计算资源来不断重新布局和渲染页面。因此,在开发网页时,需要注意避免频繁的DOM读取和写入,以提高页面性能。

虚拟DOM

那就到了虚拟dom了

虚拟DOM的基本工作流程如下:

  1. 初始渲染: 当页面加载时,首次渲染时,会通过JavaScript创建一个虚拟DOM树,这个虚拟DOM树的结构和真实DOM树相同。
  2. 状态变更: 当应用状态发生变化时(用户交互、数据变更等),不直接操作实际的DOM,而是在JavaScript中对虚拟DOM进行操作。这样的操作是在内存中进行的,非常轻量。
  3. 虚拟DOM Diff: 在状态变更后,生成新的虚拟DOM树。接着,通过比较新旧虚拟DOM树的差异(Diff算法),找到需要更新的部分。
  4. 局部更新: 根据差异,只更新需要变化的部分到实际的DOM树。这样就避免了对整个DOM树的重排和重绘,提高了性能。

通过使用虚拟DOM,开发者可以更轻松地进行状态管理和UI更新,而不必担心频繁的DOM操作导致的性能问题。

然后从双缓存和MVC模式角度来讲讲虚拟DOM。

双缓存

比如说一个比较大比较复杂的页面,需要多次计算才可以完成,如果每次计算一部分都写入到缓冲区,那给用户呈现的效果就是一块一块的出来,使用双缓存,可以将计算的中间结果先放到一个缓冲区中,等全部计算完之后将计算结果复制到显示的缓冲区中,这样给用户的体验会好一些。

也就是可以把虚拟DOM看成是真实DOM的一个buffer,和图形显示一样,在完整的操作之后在应用到真实DOM中,这样子就可以减少一些无用的更新。

来,官方一点的讲解:

双缓存是一种用于避免闪烁和提高渲染效率的图形技术。

  • 实际DOM作为前台缓存: 当浏览器渲染页面时,它使用实际的DOM来呈现内容。这就好像是前台缓存,用于展示当前的页面状态。
  • 虚拟DOM作为后台缓存:虚拟DOM就可以看作是后台的缓存,用于在内存中维护一个状态的表示。在状态发生变化时,首先更新虚拟DOM,然后再将变化应用到实际的DOM。这个过程避免了直接在实际DOM上进行频繁的操作,提高了性能。

通过使用双缓存,可以减少对实际DOM的直接操作,降低页面的渲染成本,同时避免了用户在页面更新时看到的闪烁效果。

MVC模式

MVC是有模型、视图和控制器三部分组成,核心思想就是将数据和视图分离,数据和视图之间的通信通过控制器来完成。 没错MVVM、MVP都是基于MVC衍生的。

虚拟DOM与MVC模型的关系可以理解为:

  • Model: 虚拟DOM中的数据状态和应用状态。
  • View: 虚拟DOM的结构和展示。
  • Controller: 虚拟DOM的操作和更新。
相关推荐
everyStudy43 分钟前
前端五种排序
前端·算法·排序算法
甜兒.2 小时前
鸿蒙小技巧
前端·华为·typescript·harmonyos
她似晚风般温柔7894 小时前
Uniapp + Vue3 + Vite +Uview + Pinia 分商家实现购物车功能(最新附源码保姆级)
开发语言·javascript·uni-app
Jiaberrr5 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
everyStudy6 小时前
JS中判断字符串中是否包含指定字符
开发语言·前端·javascript
城南云小白6 小时前
web基础+http协议+httpd详细配置
前端·网络协议·http
前端小趴菜、6 小时前
Web Worker 简单使用
前端
web_learning_3216 小时前
信息收集常用指令
前端·搜索引擎
Ylucius6 小时前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
tabzzz6 小时前
Webpack 概念速通:从入门到掌握构建工具的精髓
前端·webpack