浏览器原理 25 # 虚拟DOM和实际的DOM有何不同?

简介: 浏览器原理 25 # 虚拟DOM和实际的DOM有何不同?

说明

浏览器工作原理与实践专栏学习笔记



DOM 的缺陷

操作 DOM 触发样式计算、布局、绘制、栅格化、合成等任务,还有可能引起重绘或者合成操作。另外,对于 DOM 的不当操作还有可能引发强制同步布局和布局抖动的问题,这些操作都会大大降低渲染效率。


什么是虚拟 DOM


虚拟 DOM 要解决什么事情


将页面改变的内容应用到虚拟 DOM 上,而不是直接应用到 DOM 上。


变化被应用到虚拟 DOM 上时,虚拟 DOM 并不急着去渲染页面,而仅仅是调整虚拟 DOM 的内部状态,这样操作虚拟 DOM 的代价就变得非常轻了。


在虚拟 DOM 收集到足够的改变时,再把这些变化一次性应用到真实的 DOM 上。


虚拟 DOM 执行流程


结合 React 流程画的一张虚拟 DOM 执行流程图


20210525204031180.png


创建阶段:首先依据 JSX 和基础数据创建出来虚拟 DOM,它反映了真实的 DOM 树的结构。然后由虚拟 DOM 树创建出真实 DOM 树,真实的 DOM 树生成完后,再触发渲染流水线往屏幕输出页面。


更新阶段:如果数据发生了改变,那么就需要根据新的数据创建一个新的虚拟 DOM 树;然后 React 比较两个树,找出变化的地方,并把变化的地方一次性更新到真实的 DOM 树上;最后渲染引擎更新渲染流水线,并生成新的页面。



React Fiber 更新机制

通过上图可以知道,当有数据更新时,React 会生成一个新的虚拟 DOM,然后拿新的虚拟 DOM 和之前的虚拟 DOM 进行比较,这个过程会找出变化的节点,然后再将变化的节点应用到 DOM 上。


重点关注下比较过程,最开始的时候,比较两个虚拟 DOM 的过程是在一个递归函数里执行的,其核心算法是 reconciliation。通常情况下,这个比较过程执行得很快,不过当虚拟 DOM 比较复杂的时候,执行比较函数就有可能占据主线程比较久的时间,这样就会导致其他任务的等待,造成页面卡顿。为了解决这个问题,React 团队重写了 reconciliation 算法,新的算法称为 Fiber reconciler,之前老的算法称为 Stack reconciler。


关于协程可以看看之前的笔记:浏览器原理 19 # JavaScript 引擎是如何实现 async / await 以同步的方式来编写异步代码的?


协程的另外一个称呼就是 Fiber,所以在这里我们可以把 Fiber 和协程关联起来,那么所谓的 Fiber reconciler 就是在执行算法的过程中出让主线程,这样就解决了 Stack reconciler 函数占用时间过久的问题。



双缓存视角看虚拟 DOM

比如:一幅完整的画面,可能需要计算多次才能完成,如果每次计算完一部分图像,就将其写入缓冲区,那么就会造成一个后果,那就是在显示一个稍微复杂点的图像的过程中,你看到的页面效果可能是一部分一部分地显示出来,因此在刷新页面的过程中,会让用户感受到界面的闪烁。


而使用双缓存,可以让你先将计算的中间结果存放在另一个缓冲区中,等全部的计算结束,该缓冲区已经存储了完整的图形之后,再将该缓冲区的图形数据一次性复制到显示缓冲区,这样就使得整个图像的输出非常稳定。


双缓存是一种经典的思路,应用在很多场合,能解决页面无效刷新和闪屏的问题,虚拟 DOM 就是双缓存思想的一种体现。你可以把虚拟 DOM 看成是 DOM 的一个 buffer,和图形显示一样,它会在完成一次完整的操作之后,再把结果应用到 DOM 上,这样就能减少一些不必要的更新,同时还能保证 DOM 的稳定输出。


MVC 模式中虚拟 DOM 所扮演的角色


MVC 是一个非常重要且应用广泛的模式,因为它能将数据和视图进行分离,在涉及到一些复杂的项目时,能够大大减轻项目的耦合度,使得程序易于维护。


MVC 的基础结构:

20210525213442594.png



MVC 的整体结构比较简单,由模型、视图和控制器组成,其核心思想就是将数据和视图分离,也就是说视图和模型之间是不允许直接通信的,它们之间的通信都是通过控制器来完成的。


基于 React 和 Redux 构建 MVC 模型:


20210525214021165.png



在该图中,可以把虚拟 DOM 看成是 MVC 的视图部分,其控制器和模型都是由 Redux 提供的。

其具体实现过程如下:


   图中的控制器是用来监控 DOM 的变化,一旦 DOM 发生变化,控制器便会通知模型,让其更新数据;


   模型数据更新好之后,控制器会通知视图,告诉它模型的数据发生了变化;


   视图接收到更新消息之后,会根据模型所提供的数据来生成新的虚拟 DOM;


   新的虚拟 DOM 生成好之后,就需要与之前的虚拟 DOM 进行比较,找出变化的节点;


   比较出变化的节点之后,React 将变化的虚拟节点应用到 DOM 上,这样就会触发 DOM 节点的更新;


   DOM 节点的变化又会触发后续一系列渲染流水线的变化,从而实现页面的更新。


分析基于 React 或者 Vue 这些前端框架时,先重点把握大的 MVC 骨架结构,然后再重点查看通信方式和控制器的具体实现方式。



拓展


其实虚拟 DOM 主要是一个抽象层,用于描述视图,抽象视图变化,诞生主要目的是跨平台。所以才有 React Native,weex。解决 js 操作 dom 性能问题只是附带的,而且虚拟 DOM 是有代价的,在页面结构简单操作也简单的情况下相对 js 操作 DOM 并不一定会有优势。


另外感兴趣的可以看:


snabbdom


可以看一下这篇文章:Virtual Dom库snabbdom代码解析


可以从下面三个方向稍微了解一下 snabbdom


   第一个是js模拟的dom节点vnode的结构


   第二个是diff算法


   第三个是有了diff如何打patch的








目录
相关文章
|
2月前
|
JavaScript 前端开发 算法
React技术栈-虚拟DOM和DOM diff算法
这篇文章介绍了React技术栈中的虚拟DOM和DOM diff算法,并通过一个实际案例展示了如何使用React组件和状态管理来实现动态更新UI。
38 2
|
23天前
|
JavaScript 前端开发 算法
真实DOM和虚拟DOM有哪些区别?
本文介绍了真实DOM和虚拟DOM的概念、使用方式、优势、劣势、使用场景、影响因素、开发效率和性能对比。真实DOM是浏览器提供的原生接口,直接操作简单直观,但频繁操作会导致性能损耗。虚拟DOM是真实DOM的抽象表示,通过比较差异减少DOM操作,适用于大规模数据变更和复杂交互的页面。开发者应根据具体需求选择合适的DOM操作方式,以提高页面性能和开发效率。
57 1
真实DOM和虚拟DOM有哪些区别?
|
15天前
|
XML 编解码 JavaScript
DOM(文档对象模型)和 BOM(浏览器对象模型)
【10月更文挑战第19天】在前端开发中,理解 DOM(文档对象模型)和 BOM(浏览器对象模型)是至关重要的。它们是 Web 开发的基础,为我们提供了与网页文档和浏览器进行交互的能力。
|
27天前
|
XML JavaScript 数据格式
XML DOM 浏览器差异
XML DOM 浏览器差异
|
1月前
|
XML JavaScript 数据格式
XML DOM 浏览器差异
XML DOM 浏览器差异
|
1月前
|
前端开发 JavaScript 异构计算
简述浏览器的渲染原理
浏览器渲染原理主要包括以下步骤:1)解析HTML文档生成DOM树;2)解析CSS生成CSSOM树;3)结合DOM与CSSOM生成渲染树;4)布局计算(回流)确定元素大小和位置;5)绘制(Paint)将节点转为图形内容;6)合成(Composite)多层图像。整个过程从文档解析到最终输出完整网页,并通过优化技术提升性能。
|
1月前
|
XML JavaScript 数据格式
XML DOM 浏览器差异
XML DOM 浏览器差异
|
25天前
|
XML JavaScript 数据格式
XML DOM 浏览器差异
XML DOM 浏览器差异
|
29天前
|
XML JavaScript 数据格式
XML DOM 浏览器差异
XML DOM 浏览器差异
|
1月前
|
XML JavaScript 数据格式
XML DOM 浏览器差异
XML DOM 浏览器差异