发布订阅之理解vue响应式基本原理

154 阅读2分钟

相关的文章很多,写的也很类似,这里我尝试从观察者模式的解释。动手写一写比看十边都有用。
首先举一个栗子,邮局(dep类)与邮递员(watcher类观察者),

邮递员工作,观察信来了就送信,不关心细节(data修改就更新视图)watcher.update()。
邮局工作,处理信件告知邮递员哪些信件你负责送即收集依赖到数组dep.addsub(),通知邮递员立刻马上送货,不然没工资触发依赖 dep.notify()

function observer(obj){ // 这个其实就是处理 观察者和订阅者的关系。处理邮局与邮递员的关系。

	for(let [key,val] of Object.entries(obj)){
		defineReactive(obj, key, val) //传入data对象,key,val
	}
}

function defineReactive (obj, key, val) {

	/* 一个Dep类对象 */
	const dep = new Dep();

    Object.defineProperty(obj, key, {
        enumerable: true,       /* 属性可枚举 */
        configurable: true,     /* 属性可被修改或删除 */

        get(){ 
        	//render funtion 渲染dom的时候 肯定会用到data,所以就会触发这里get。

        	dep.addSub(new Watcher())

        	//1·收集依赖,其实就是收集(哪些信需要哪个邮递员去送信)/也就是哪个观察者订阅了哪个事件/哪个组件用了哪些data数据。

		  	//2·访问data.a,dep实例(邮局)开始收集watcher实例(邮递员a你负责送a的信),访问data.b 就收集邮递员b,他们是分别去送不同的信。

			//3·watcher也就是观察者,就是一个中间人,干活的邮递员,不需要知道细节只负责送自己负责的信就好,观察到变化就开始干活(更新视图)我只观察我负责的部分,我不需要了解细节,,

			return val
		},
        set(){
        	//触发依赖过程很好理解//,
        	//1·dep(邮局)通知 *所有* 邮递员现在立刻去送信dep.notify(),不然不开工资。至于怎么送的过程也就是更新视图(watcher.update),邮局dep不关心。
			dep.notify()
		}
    });
}

class Dep{ 
	//订阅者,邮局
	constructor(){
		this.subs =[] 
		//这是一个存储队列。
	}
	addSub(sub){
		//收集依赖,理解为 邮件很多,需要添加大量的邮递员。收集信件并告知邮递员哪些信件送到哪里。这是邮局的功能。
		this.subs.push(sub)
	}
	notify(){
		//这里就是触发依赖, 通知快递员 我这收集了好多信,那个张三的信 你可以送了,
		this.subs.forEach(sub=>{
			sub.update() 
			//这里sub就是watcher实例,埋头苦干,去快乐送信。
		})
	}
}

class Watcher{ //观察者,邮递员
	constructor(){

	}
	update(){
		console.log('开始送信了')
	}
}

class Vue{
	constructor(options){
		this._data = options.data

		observer(this._data);
        /* 新建一个Watcher观察者对象 */
        new Watcher();
        /* 在这里模拟render的过程,为了触发test属性的get函数 */
        console.log('render~', this._data.test);
	}
}

let o = new Vue({
	data:{
		test:0,
	}
})

o._data.test = '10件' //改动触发送信操作