Vue源码解读学习

Vue源码

观察者模式 & 发布订阅

观察者模式:中心一对多 + 系统单点间的灵活和拓展(广播的方式)

发布订阅:将注册列表遍历发布给订阅者

initInject initState initProvide他们挂载顺序为什么这样设计?

initstate 是将 data | props & methods & watch | computed 初始化

那么你需要 provide 就必须要存在 data | props...等等初始化数据

inject 为什么要在 initstate 之前呢?

因为如果我们当前实例有用到 Inject 的地方 那么必须要先 inject 才能操作它

Vue3做了哪些优化

源码结构上:

monorepo(原子结构 可独立拆分引用)(可作业务上的拆分)

性能上:

移除了很多使用率比较低的api

tree-shaking => 打包产物优化 按需引入

编译上:
复制代码
compoile阶段   静态模板 进行分析 => 分析树 <= PatchFlag
数据劫持上:
复制代码
Object.defineProperty 本身无法检测对象属性的增加或者删除
Vue2使用$set $delete  数组 push pop ... 层级较深 => 递归遍历
Vue3 proxy => 底层优化
模板编译分段

词法分析阶段: template(baseCompile => baseParse) => AST

指令和语法的转化阶段(transform => node节点打标签): AST => 解析不同的节点进行区分 => 不同类型转化

可执行函数的生成阶段(generate):转化后的AST生成渲染函数

基于Proxy的响应式

数据劫持 | 数据响应(reactive):数据变化 => 函数监听执行

依赖收集(effect)

当前vm实例上挂载effect => 当前activeEffect切换为effect => 在effect上创建deps

属性,用于传递依赖

Vue2中 Watcher和Dep之间怎么处理的?

本质上就是 当render函数读取getter响应式变量的时候 会触发依赖收集 创建一个Watcher

当这个变量被setter的时候 会告诉Watcher去让组件重新生成render函数

手写一个响应式

js 复制代码
class Vue {
    constructor(options) {
        const data = options.data
        this._data = data

        // 数据劫持 => initData
        _proxy(this, '_data', data)

        // 核心逻辑
        observe(data)

        new Watch(this, function() {
            return data.name + '创建响应式'
        }, function() {
            console.log('watch cb:', this.value)
        })
    }
}

const _proxy = function(vm, sourceKey, data) {
    const keys = Object.keys(data);

    keys.forEach(key => {
        Object.defineProperty(vm, key, {
            get() {
                return vm[sourceKey][key]
            },
            set(val) {
                vm[sourceKey][key] = val
            }
        })
    })
}

const observe = function(data) {
    const ob = new Observer(data)
}

class Observer {
    constructor(data) {
        this.walk(data)
    }
    walk(data) {
        Object.keys(data).forEach(key => {
            defineReactive(data, key)
        })
    }
}

const defineReactive = function(obj, key) {
    let val = obj[key]
    const dep = new Dep()

    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get() {
            console.log('依赖收集')
            dep.depend()
            return val
        },
        set(newVal) {
            console.log('派发更新')
            val = newVal
            dep.notify()
        }
    })
}

class Dep {
    constructor() {
        this.id = Dep.uid++
        this.subs = []
    }

    addSub(sub) {
        this.subs.push(sub)
    }

    depend() {
        if (Dep.target) {
            Dep.target.addDep(this)
        }
    }

    notify() {
        this.subs.forEach(sub => sub.update())
    }

    removeSub(sub) {
        const subIndex = this.subs.indexOf(sub)
        this.subs.splices(subIndex, 1)
    }
}
Dep.uid = 0
Dep.target = null

class Watch {
    constructor(vm, render, cb) {
        this.vm = vm
        this.render = render
        this.cb = cb

        this.deps = []
        this.depsIds = new Set()
        this.newDeps = []
        this.newDepsIds = new Set()

        this.value = this.get()
        this.cb(this.value)
    }

    get() {
        Dep.target = this
        this.newDeps = []
        this.newDepsIds = new Set()

        const value = this.render()

        Dep.target = null
        this.deps.forEach(oldDep => {
            const notExistInNewDeps = !this.newDepsIds.has(oldDep.id)
            if (notExistInNewDeps) {
                oldDep.removeSub(this)
            }
        })
        this.deps = this.newDeps
        this.depsIds = this.newDepsIds

        return value
    }

    addDep(dep) {
        const depId = dep.id
        if (!this.newDepsIds.has(depId)) {
            this.newDeps.push(dep)
            this.newDepsIds.add(depId)

            if (!this.depsIds.has(depId)) {
                dep.addSub(this)
            }
        }
    }

    update() {
        this.value = this.get()
        this.cb(this.value)
    }
}

let zhaowa = new Vue({
    data: {
        name: 'yy',
        course1: 100,
        course2: 99
    }
})

zhaowa.course1 = 1
zhaowa.course2 = 2
相关推荐
酷讯网络_24087016015 分钟前
区块粮仓宠物NFT源码区块狗/抢购转让预约区块投资理财系统
学习·开源·宠物
Generalzy42 分钟前
从本地 Demo 到生产级检索:Milvus 学习笔记(3)
笔记·学习·milvus
名字还没想好☜1 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司1 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能
心中有国也有家2 小时前
AtomGit Flutter 鸿蒙客户端:ModalBottomSheet 实战
android·javascript·学习·flutter·华为·harmonyos
tyqtyq222 小时前
求职信生成:AI 智能求职信撰写系统的鸿蒙实现
人工智能·学习·华为·生活·harmonyos
MartinYeung52 小时前
[论文学习]PrivacyLens:评估语言模型在行动中的隐私规范意识
人工智能·学习·语言模型
凉、介3 小时前
Virtio 系列(一):框架概览
笔记·学习·嵌入式·虚拟化·virtio
仙人球部落4 小时前
-python-LangGraph框架(3-31-LangGraph 「合并式状态管理」的原理与实践)
开发语言·javascript·python
小心亦新4 小时前
STM32学习12--串口2收发数据包
学习