vue2源码--依赖收集

vue2源码–依赖收集

Dep

Dep是用来收集渲染的变量的。比如 {{age}} {{text}} 需要渲染,但是在后续中改变了age, text, 以及hobby这个变量,只会收集需要渲染的数据。

Watcher

通知dep的变化,被dep收集
一个dep可以有多个watcher 一个属性可以在多个组件中使用
一个watcher也可以有多个dep 一个组件可以使用多个属性
Observer 将数据定义为响应式,每个 Observer 实例都有自己的 Dep 来管理依赖。实例化 Wacther 的时候进行求值会触发 getter ,进而执行 dep.depend() 将当前 Wacther 加入 Dep 维护的依赖列表,这就是依赖收集过程。
数据发生变化触发 setter 执行 dep.notify,Dep 会执行所有依赖的 update 方法并加入异步更新队列,这就是触发依赖过程。

渲染的原理

  1. 将render函数传入watcher
  2. render函数执行get()函数
  3. 渲染数据,每个数据都有dep,只有被渲染的才会有dep.id
  4. 依次渲染数据,渲染完毕,将dep.target设置为null
  5. 如有变更,会重新执行渲染函数,即重新watcher。

dep.js

let id = 0
class Dep {
    constructor() {
        this.id = id++
        this.subs = []
    }
    addSub(watcher) {
        console.log(7)
        console.log("{addSub  dep}")// 记录watcher
        this.subs.push(watcher)
    }
    depend() {
        // this.subs.push(Dep.target)
        console.log("{depend}")
        Dep.target.addDep(this)
    }
    notify() {
        console.log('{notify}')
        this.subs.forEach(watcher => watcher.update())
    }
}
Dep.target = null
export default Dep

watcher.js

import Dep from './dep'

let id = 0
class Watcher {
    constructor(vm, exprOrFn, options) {  //vm是实例, exprOrFn是render函数。
        this.id = id++
        this.renderWatcher = options  // off
        this.getter = exprOrFn // 调用这个函数,可以发生取值操作
        this.deps = [] // 计算属性和清理工作
        this.depsId = new Set()  // 去重
        this.get()
    }

    addDep(dep) {
        console.log(5)
        console.log(dep)
        console.log("[addDep watcher]")
        let id = dep.id
        if (!this.depsId.has(id)) {
            console.log(6)
            this.deps.push(dep)
            this.depsId.add(id)
            dep.addSub(this)
        }
    }
    get() {
        console.log("[get]")
        Dep.target = this
        console.log(1)
        this.getter()
        Dep.target = null
    }
    update() {
        console.log("[update]")
        this.get()
    }
}
export default Watcher

observe/index.js

import {newArrayProto} from "./array";
import Dep from "./dep";

class Observer {
    constructor(data) {
        // data.__ob__ = this
        this.dep = new Dep()
        Object.defineProperty(data, '__ob__', {
            value:this,
            enumerable:false
        })
        if (Array.isArray(data)) {
            data.__proto__ = newArrayProto
        } else{
            this.walk(data)
        }
    }
    walk(data) {
        Object.keys(data).forEach(key => {
            // debugger
            definedReactive(data,key,data[key])
        })
    }
    observeArray(data) {
        data.forEach(item => observe(item))
    }
}
export function definedReactive(target, key, value) {

    observe(value)
    let dep = new Dep()
    Object.defineProperty(target, key, {
        get() {
            if (Dep.target) {
                console.log(4)
                console.log("value", value)
                dep.depend()
            }
            return value
        },
        set(newValue) {
            if(value === newValue) return
            observe(newValue)
            value = newValue
            dep.notify()
        }
    })
}
export function observe(data) {
    if (typeof data !== 'object' || data == null) {
        return
    }
    if (data.__ob__ instanceof Observer) {
        return data.__ob__
    }
    return new Observer(data)
}

上面代码中的console.log(1)等等可以帮助理解代码逻辑

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值