Gahing's blog Gahing's blog
首页
知识体系
  • 前端基础
  • 应用框架
  • 工程能力
  • 应用基础
  • 专业领域
  • 业务场景
  • 前端晋升 (opens new window)
  • Git
  • 网络基础
  • 算法
  • 数据结构
  • 编程范式
  • 编解码
  • Linux
  • AIGC
  • 其他领域

    • 客户端
    • 服务端
    • 产品设计
软素质
  • 面试经验
  • 人生总结
  • 个人简历
  • 知识卡片
  • 灵感记录
  • 实用技巧
  • 知识科普
  • 友情链接
  • 美食推荐 (opens new window)
  • 收藏夹

    • 优质前端信息源 (opens new window)
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Gahing / francecil

To be best
首页
知识体系
  • 前端基础
  • 应用框架
  • 工程能力
  • 应用基础
  • 专业领域
  • 业务场景
  • 前端晋升 (opens new window)
  • Git
  • 网络基础
  • 算法
  • 数据结构
  • 编程范式
  • 编解码
  • Linux
  • AIGC
  • 其他领域

    • 客户端
    • 服务端
    • 产品设计
软素质
  • 面试经验
  • 人生总结
  • 个人简历
  • 知识卡片
  • 灵感记录
  • 实用技巧
  • 知识科普
  • 友情链接
  • 美食推荐 (opens new window)
  • 收藏夹

    • 优质前端信息源 (opens new window)
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 前端基础

  • 应用框架

    • UI 框架

      • Angular

      • React

      • Solid

      • Svelte

      • Vue

        • Vue 项目中的 data-v-xxx 是怎么生成的
        • Vue之从零编写一个ContextMenu(右键菜单)插件
        • Vue 第一个组件,浏览器后退无法触发beforeRouteLeave的问题与解决
        • Vue问题记录
        • vue 中 updated 的执行时机
        • 源码解析

          • Vue 源码解析-0.前置准备
          • Vue实例化过程
          • Vue响应式原理
          • Vue响应式之data
          • Vue响应式之props
          • Vue响应式之computed
          • Vue响应式之watch
          • Vue响应式之异步更新与nextTick
          • Vue响应式之组件更新
            • 前言
            • 从 updateComponent 入手
            • dom diff
            • 父组件数据更新导致子组件变动,整个过程如下:
            • vdom 更新的时候,真实 dom 是一次次被更新么?
            • 与 react diff 的区别
      • 框架本质

    • 开发框架

    • 组件库

  • 工程能力

  • 应用基础

  • 专业领域

  • 业务场景

  • 大前端
  • 应用框架
  • UI 框架
  • Vue
  • 源码解析
gahing
2019-12-10
目录

Vue响应式之组件更新

# 前言

前面的文章说过,当数据发生变化时,会触发渲染 Watcher 的回调函数,进而执行组件更新。

本文就开始来讲讲这个组件更新到底做了哪些事,可能涉及的知识点有:

  1. 模板解析
  2. Virtual DOM
  3. VNode
  4. dom diff 过程

部分知识点只会简单点下,详细的再单独一篇文章讲解

# 从 updateComponent 入手

# dom diff

没看源码,先猜测下策略

如果是新旧节点不同,最简单的情况,做个替换即可

如果是新旧节点相同:值不变则结束处理,文本节点特殊处理,否则比较子节点,即两个列表做个对比

这里提到了一个节点是否相同的概念,猜测应该是判断 key 和节点类型

回到比较子节点,举例:

旧:ABCDE
新:CAFBDG
1
2

遍历新列表的每个节点,每次再去旧列表中找,找到了放对应位置(继续做判断新旧节点相同类型是否更新的操作),没找到则新建,时间复杂度O(n²)

一个个进行比对,不相同则替换,举例

// 旧
<div>
 <A/>
 <B/>
 <C/>
 <D/>
 <E/>
</div>
1
2
3
4
5
6
7
8

还要注意一点,如果子节点不带 key 且节点类型相同,在判断节点相同的处理上判断这两个节点相同,保留了原节点的内部状态,产生一系列的 bug

因此子节点类型相同的情况,需要带 key ,带key还有个好处,一轮查询由O(n) 变为 O(1) 可以提高性能

举例

<body>
  <div id="el">
  </div>
  <!-- using string template here to work around HTML <option> placement restriction -->
  <script type="text/x-template" id="demo-template">
      <div>
        <test v-if="flag" name="s1">
        </test>
        <test v-else name="s2">
        </test>
      </div>
    </script>
  <script type="text/x-template" id="test-template">
      <div>
        {{dname}}
      </div>
    </script>
  <script>
    Vue.component('test', {
      props: ['name'],
      template: '#test-template',
      data: function () {
        return {
          dname: this.name
        }
      },
    })
    var vm = new Vue({
      el: '#el',
      template: '#demo-template',
      data: {
        flag: true,
      }
    })
  </script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

不带 key 的情况, 控制台执行 vm.$data.flag = false 去触发 patch

diff 比较时判断这前后节点一样,直接用了原来的节点了,导致内部状态不变, dname 还是原来的 s1

加上 key 后, patch 时就会认为这不是相同的节点,做个替换,然后就可以得到 s2 了

<test v-if="flag" name="s1" key="s1">
</test>
<test v-else name="s2" key="s2">
</test>
1
2
3
4

举例

ABD // 旧 vdom
=> 
BADC // 新 vdom
BADC // 真实 dom
1
2
3
4

如何高效的进行移动呢?

新旧 vdom 各有一个头尾节点,进行四次比较,移动真实 dom 和指针

os = A oe = D
ns = B ne = C
1
2

四种比较都不满足,找到 ns 在旧 vdom 的节点相同的节点并做比较,没找到的话说明要新建 ns 节点

这个过程可能还用了 key map 这类的做加速,没 key 的话查找是 O(n) 的时间复杂度

# 父组件数据更新导致子组件变动,整个过程如下:

_render: 递归解析模板(不会深入解析组件),通过内部 createElement 方法生成 VNode

_update: 新旧 vnode 执行 patchVnode

patchVnode: vdom 的 diff 过程。若 vnode 不一致,对该 vnode 进行 _render 和 _update ,这是一个 dfs 的过程。若组件 vnode 不变,仅参数不同,则执行 prepatch ,将新参数传入组件,执行 updateChildComponent 对该组件进行更新

# vdom 更新的时候,真实 dom 是一次次被更新么?

看了下貌似是,如果是批量插入的,可能做了优化

# 与 react diff 的区别

编辑 (opens new window)
上次更新: 2024/09/01, 23:56:56
Vue响应式之异步更新与nextTick
浅谈DOM DIFF

← Vue响应式之异步更新与nextTick 浅谈DOM DIFF→

最近更新
01
浅谈代码质量与量化指标
08-27
02
快速理解 JS 装饰器
08-26
03
Vue 项目中的 data-v-xxx 是怎么生成的
09-19
更多文章>
Theme by Vdoing | Copyright © 2016-2024 Gahing | 闽ICP备19024221号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式