为何出现虚拟DOM?

10/11/2022 Virtual Dom

# 前言

DOM本身其实是有一些缺陷的,虚拟DOM的出现就是为此而诞生的,React、Vue都使用了虚拟DOM技术。

# DOM缺陷

需要先了解DOM树生成相关知识:

DOM提供了一组JavaScript接口用于操作树节点的,JavaScript操作DOM会影响到整个渲染流水线。可能触发:

  • 重排:样式计算、布局、绘制、栅格化、合成more...
  • 重绘
  • 合成
  • 强制同步布局
  • 布局抖动 对于复杂的页面,修改DOM树,执行一次重排or重绘等等都是非常耗时的,导致性能问题。

需要一种方案减少JavaScript对DOM的操作 => 虚拟DOM

# 虚拟DOM

# 要做的事情

  • 页面发生变化的内容作用到虚拟DOM上,而非直接作用到DOM上。
  • 变化作用到虚拟DOM上,不直接应用到DOM渲染页面,只调整虚拟DOM内部状态(操作虚拟DOM代价相对较低)。
  • 当虚拟DOM收集到足够的变化,再一次性将这些变化作用到真实DOM。

# React虚拟DOM

  • 创建虚拟DOM => 数据、JSX创建虚拟DOM,虚拟DOM创建真实DOM,触发渲染流程输出页面。
  • 更新虚拟DOM => 数据变化,根据新数据创建一个新的虚拟DOM,React进行新旧虚拟DOM对比,找出变化的点,将变化的点一次性更新到真实DOM,触发渲染引擎更新流程输出新页面。 React虚拟DOM流程

# React Fiber

React在新旧虚拟DOM比较的过程中,是在一个递归函数中执行的(算法reconciliation)。一般情况这个过程执行比较快,但是当虚拟DOM本身也很复杂的时候,执行比较函数有可能占据主线程很久,这样会导致其他任务等待,页面会卡顿。为了解决这个问题,React重写reconciliation算法(Stack reconciler),改新算法Fiber reconciler。
Fiber可以和协程关联起来,算法Fiber reconciler是在执行过程中能够出让主线程,避免函数占用过久的问题。 关于协程一些点

# 设计模式

# 双缓存

开发游戏或处理其他图像的过程中,屏幕从前缓冲区读取数据然后显示。但很多图形都很复杂且需要大量运算,比如一幅完整的画面,可能需要计算多次才能完成,如果每次计算完一部分图像,就将其写入缓冲区,那么会造成一个后果,就是在显示一个稍微复杂点的图像的过程中,会看到的页面效果可能是一部分一部分地显示出来,在页面刷新的过程中,会让用户感到画面闪烁。
使用双缓存,先将计算的中间结果存放在另一个缓冲区,等全部的计算结束,该缓冲区已经存储了完整的图形,再将该缓冲区的图形数据一次性复制到显示缓冲区,这样使得整个图像的输出非常稳定。
可以把虚拟DOM看成是DOM的一个buffer,和图形显示一样,会在完成一次完整的操作之后,再去把结果应用到DOM上,能减少一些不必要的更新,同时还能保证DOM的稳定输出。

# MVC模式

MVC将数据和视图进行分离,面对复杂项目,大大降低项目耦合度,便于维护。
核心点:

  • 数据和视图分离,不允许直接通信。
  • 通信通过控制器来完成。

一般的通信路径 => 视图发生变化,通知控制器,控制器判断是否更新数据模型。基于MVC演变出MVP(Model-View-Presenter)、MVVM。 MVC设计模式

# React + Redux => MVC

React(虚拟DOM)=> View视图 Redux => Model数据模型 + Controller控制器

  • 控制器监听DOM变化,DOM发生变化事件,控制器通知模型更新数据;
  • 模型数据更新完毕,控制器通知视图模型数据发生了变化;
  • 视图接收到通知,根据模型数据生成新虚拟DOM;
  • 新旧虚拟DOM进行比较,找出变化的节点;
  • 变化的虚拟DOM => 作用到DOM触发更新;
  • DOM变化触发渲染流程; React Redux MVC

# 总结

  • 操作DOM会触发一系列渲染流程;
  • 虚拟DOM减少了一些对DOM不必要的操作;
  • 虚拟DOM是双缓存思想的一种体现,解决页面的无效刷新和闪屏;
Last Updated: 11/2/2022, 5:11:53 PM