粥里有勺糖

vuePress-theme-reco 粥里有勺糖    2018 - 2023
粥里有勺糖 粥里有勺糖

Choose mode

  • dark
  • auto
  • light
关于我
备战春秋
  • 心得总结
  • 校招考点汇总
  • 面经汇总
  • 复习自查
技术笔记
  • 技术教程
  • 模板工程
  • 源码学习
  • 技术概念
  • 个人作品
  • 学习笔记
计算机基础
  • 算法与数据结构
  • 操作系统
  • 计算机网络
  • 设计模式
  • 剑指offer
大前端
  • javascript
  • vue
  • html
  • css
  • 🌏浏览器专题
  • Web性能优化
  • regexp
  • node
面试
  • 问解
  • javascript
  • css
  • 手撕代码
  • 性能优化
  • 综合问题
  • 面经汇总
  • 小程序
手撕代码
  • 数据结构与算法
  • javascript
  • css
个人站点
  • GitHub (opens new window)
  • 博客园 (opens new window)
  • 掘金 (opens new window)
线上作品
  • 轻取(文件收集) (opens new window)
  • 个人图床 (opens new window)
  • 考勤小程序 (opens new window)
  • 时光恋人 (opens new window)
  • 在线简历生成 (opens new window)
留言板
Github (opens new window)
author-avatar

粥里有勺糖

285

文章

40

标签

关于我
备战春秋
  • 心得总结
  • 校招考点汇总
  • 面经汇总
  • 复习自查
技术笔记
  • 技术教程
  • 模板工程
  • 源码学习
  • 技术概念
  • 个人作品
  • 学习笔记
计算机基础
  • 算法与数据结构
  • 操作系统
  • 计算机网络
  • 设计模式
  • 剑指offer
大前端
  • javascript
  • vue
  • html
  • css
  • 🌏浏览器专题
  • Web性能优化
  • regexp
  • node
面试
  • 问解
  • javascript
  • css
  • 手撕代码
  • 性能优化
  • 综合问题
  • 面经汇总
  • 小程序
手撕代码
  • 数据结构与算法
  • javascript
  • css
个人站点
  • GitHub (opens new window)
  • 博客园 (opens new window)
  • 掘金 (opens new window)
线上作品
  • 轻取(文件收集) (opens new window)
  • 个人图床 (opens new window)
  • 考勤小程序 (opens new window)
  • 时光恋人 (opens new window)
  • 在线简历生成 (opens new window)
留言板
Github (opens new window)
  • Vue

    • 简介
    • 响应式基本原理
    • 路由原理
    • 生命周期钩子
    • 组件通信
    • extend API
    • mixin与mixins
    • computed与watch
    • keep-alive
    • v-show 与 v-if
    • ❤运行机制概述
    • ❤响应式系统的依赖收集追踪原理
    • ❤VNode实现
    • 编译template的过程
    • 数据状态更新时的差异 diff 及 patch 机制

响应式系统的依赖收集追踪原理

vuePress-theme-reco 粥里有勺糖    2018 - 2023

响应式系统的依赖收集追踪原理

粥里有勺糖 2020-04-14 大前端vue

# 响应式系统的依赖收集追踪原理

# 订阅者 Dep

主要作用是用来存放 Watcher 观察者对象

class Dep{
    constructor(){
        // 存放Watcher对象
        this.subs = []
    }

    /**
     * 添加一个Watcher对象
     **/
    addSub(sub){
        this.subs.push(sub)
    }

    /**
     * 通知所有Watcher对象更新视图
     **/
    notify(){
        this.subs.forEach(sub=>{
            sub.update()
        })
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 观察者 Watcher

Dep.target = null;

class Watcher{
    constructor(){
        Dep.target = this
    }
    update(){
        console.log('更新视图')
    }
}
1
2
3
4
5
6
7
8
9
10

# 依赖收集

  • 在对象被读的时候,触发 reactiveGetter 函数把当前的 Watcher 对象(存放在 Dep.target 中)收集到 Dep 类中去
  • 当该对象被写的时候,触发 reactiveSetter 方法,通知 Dep 类调用 notify 来触发所有 Watcher 对象的 update 方法更新对应视图
function defineReactive(obj, key, val) {
    let dep = new Dep()
    Object.defineProperty(obj, key, {
        enumrable: true,
        configurable: true,
        get: function () {
            // 进行依赖搜集
            console.log('收集依赖',key);
            dep.addSub(Dep.target)
            return val
        },
        set: function (newVal) {
            if (newVal !== val) {
                dep.notify()
            }
        }
    })
}

class Vue {
    constructor(options) {
        this._data = options.data;
        observer(this._data);
        /* 新建一个Watcher观察者对象,这时候Dep.target会指向这个Watcher对象 */
        new Watcher();
        /* 模拟render的过程,触发test属性的get函数进行依赖搜集 */

        console.log('render~');
        // 触发get收集依赖
        this._data.name // 收集依赖 name
        this._data.friends.name1 // 收集依赖name1
    }
}
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

测试示例代码

let app = new Vue({
    data: {
        name: '小明',
        friends: {
            name1: '小红',
            name2: '小刚'
        }
    }
})

// 触发set
app._data.name = 1 // 更新视图
app._data.friends.name1 = 2 // 更新视图
app._data.friends.name2 = 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Edit this page (opens new window)
Last Updated: 2022/5/15 12:46:34