导航


HTML

CSS

JavaScript

浏览器 & 网络

版本管理

框架

构建工具

TypeScript

性能优化

软实力

算法

UI、组件库

Node

业务技能

针对性攻坚

AI


虚拟 DOM

🔥 为什么需要虚拟 DOM

目的:为了解决频繁操作 DOM 导致性能开销大的问题

方案:JS 运算效率 远高于 操作 DOM 效率,所以把真实 DOM 树抽象成 JS 对象树,运用 patch 算法 来用JS计算出真正需要更新的节点,最大限度地减少 DOM 操作,从而显著提高性能

  1. Vue/React 等框架都是数据驱动页面更新,让用户无需自己操作 DOM
  2. 由于操作 DOM 这个行为本身开销成本大,而数据的频繁更新会导致 DOM 也得频繁操作
  3. 所以框架本身就得想出一个解决方案,能够尽可能减少 DOM 操作
  4. 而执行 JS 的效率远高于操作真实 DOM,所以想到用 JavaScript对象树 来模拟 真实DOM树,这样一来,不直接操作 DOM ,而是操作 JS 数据。性能就能提高许多
  5. 再通过 diff 算法,把最终更新时需要操作的部分计算好,最后一次性操作 DOM
  6. 从而达到减少 DOM 操作,提升性能的目的

🔥  什么是虚拟 DOM

Virtual DOM 其实就是一棵以 JavaScript 对象(vNode节点)作为基础的树,用对象属性来描述节点,实际

是一层对真实 DOM 的抽象

基本成员:

例如:

<div id="app" class="container">
  <h1>虚拟DOM</h1>
  <ul style="color: orange">
    <li>第一项</li>
    <li>第二项</li>
    <li>第三项</li>
  </ul>
</div>

虚拟DOM表示:

{
	tag: 'div',
  props: {
  	id: 'app',
    class: 'container'
  },
  children: [
    {
    	tag: 'h1',
      children: '虚拟DOM'
    },
    {
    	tag: 'ul',
      props: { // 节点属性及绑定事件...
      	style: 'color: orange'
      },
      children: [
        {
        	tag: 'li',
          children: '第一项'
        },
        {
        	tag: 'li',
          children: '第二项'
        },
        {
        	tag: 'li',
          children: '第二项'
        }
      ]
    }
  ]
}

模板转化为视图的过程

🔥 构建虚拟DOM

获取 template

template 转 AST 语法树

AST 语法数 转 render 函数

render 函数 返回 VNode(虚拟DOM节点)

Untitled

🔥 更新视图

  1. 数据变化
  2. 触发对应 Dep(订阅者) 中的 Watcher 对象们
  3. Watchers 会调用各自的 update 函数更新视图
    1. 利用 diff 算法将新旧虚拟节点进行差异对比
    2. 根据对比结果进行 DOM 操作

总结

转化过程:

模板AST树渲染函数虚拟DOM真实DOM

其中:

🔥 虚拟 DOM 的优势

AST 抽象语法树(Abstract Syntax Tree)

源代码的抽象语法的树状描述

目的

把代码形成树状结构,然后对这个结构做分析、优化、处理,最终再把它转化为真正所需内容

🔥 应用

说白了就是字符串解析、拼接、再解析、再拼接...

template 转 AST

对源代码的数据结构化

目的

模板中有 v-showv-ifv-model 这些指令等其他内容,而这些内容是不能存在于虚拟 DOM 中的,因为真实 html 不需要它们,它们是框架所需的,类似这种东西全部都得转为 AST 后做处理,把这些多余的(相对真实html)属性都解析成对应功能并最终删除它们。例如

示例

<div id="app" style="color: red;font-size: 20px;">
  hello
  <h1>{{ name }}</h1>
  <ul>
    <li style="color: green">{{ age }}</li>
    <li>{{ info.job }}</li>
  </ul>
</div>

转为 👇🏻

{
	tag: "div",
  type: 1, // 1代表标签
  attrs: [
    {
    	name: 'id',
      value 'app'
    },
    {
    	name: 'style',
      value: {
      	'color': 'red',
        'font-size': '20px'
      }
    }
  ],
  children: [
    {
    	type: 3, // 3代表文本
      text: 'hello'
    },
    {
    	type: 1,
      tag: 'h1',
      attr: null,
      children: [
        {
        	type: 3,
          text: '{{name}}'
        }
      ]
    }
  ]
}

这不是虚拟 DOM ,只是类似。虚拟 DOM 是描述 DOM 对象(节点)的,最终是要变成真实 DOM 的

🔥 Diff算法的原理

虚拟 DOM 的最终目的就是将虚拟节点渲染到视图上。

上面的过程就是所谓的虚拟 DOM 的算法,也就是 diff 算法,它主要包括两个步骤:

Diff 同层对比

新旧虚拟DOM对比的时候,Diff算法比较只会在同层级进行, 不会跨层级比较。所以Diff算法是:广度优先算法。 时间复杂度:O(n)

Untitled

同层比较、不跨级

Untitled