vue中的观察者模式和发布订阅者模式
观察者模式
目标者对象和观察者对象有相互依赖的关系,观察者对某个对象的状态进行观察,如果对象的状态发生改变,就会通知所有依赖这个对象的观察者,
目标者对象 Subject,拥有方法:添加 / 删除 / 通知 Observer;
观察者对象 Observer,拥有方法:接收 Subject 状态变更通知并处理;
目标对象 Subject 状态变更时,通知所有 Observer。
Vue中响应式数据变化是观察者模式 每个响应式属性都有dep,dep存放了依赖这个属性的watcher,watcher是观测数据变化的函数,如果数据发生变化,dep就会通知所有的观察者watcher去调用更新方法。因此, 观察者需要被目标对象收集,目的是通知依赖它的所有观察者。那为什么watcher也要存放dep呢?是因为当前正在执行的watcher需要知道此时是哪个dep通知了自己。
class Observer {
// 需要对value的属性描述重新定义
constructor(value) {
this.walk(value); // 初始化的时候就对数据进行监控
}
walk(data) {
Object.keys(data).forEach((key) => {
defineReactive(data, key, data[key]);
});
}
}
function defineReactive(data, key, value) {
// value 可能是一个对象,要递归劫持,所以数据不能嵌套太深
observe(value);
let dep = new Dep();
Object.defineProperty(data, key, {
get() {
// 如果有 watcher,就让 watcher 记住 dep,防止产生重复的 dep, 同时 dep 也收集此 watcher
if (Dep.target) {
dep.depend();
}
return value;
},
set(newVal) {
// 数据没变动则不处理
if (value === newVal) return;
observe(newVal); // 如果新值是个对象,递归拦截
value = newVal; // 设置新的值
dep.notify(); // 通知收集的 watcher 去更新
},
});
}
function observe(data) {
// 不是对象则不处理,isObject是用来判断是否为对象的函数
if (Object.prototype.toString.call(data)!== '[object Object]') return;
// 通过类来实现数据的观测,方便扩展,生成实例
return new Observer(data);
}
observe(data)
class Dep {
static target = null
constructor() {
this.id = id++;
this.subs = []; // 存放依赖的watcher
}
depend() {
// 让正在执行的watcher记录dep,同时dep也会记录watcher
Dep.target.addDep(this);
}
addSub(watcher) {
// 添加观察者对象
this.subs.push(watcher);
}
notify() {
// 触发观察者对象的更新方法
this.subs.forEach((watcher) => watcher.update());
}
}
class Watcher {
constructor(vm, exprOrFn) {
this.vm = vm;
this.deps = [];
// 用来去重,防止多次取同一数据时存入多个相同dep
this.depId = new Set();
// exprOrFn是updateComponent
this.getter = exprOrFn;
// 更新页面
this.get();
}
get() {
Dep.target = watcher; // 取值之前,收集 watcher
this.getter.call(this.vm); // 调用updateComponent更新页面
Dep.target = null; // 取值完成后,将 watcher 删除
}
// dep.depend执行时调用
addDep(dep) {
let id = dep.id;
let has = this.depId.has(id);
if (!has) {
this.depId.add(id);
// watcher存放dep
this.deps.push(dep);
// dep存放watcher
dep.addSub(this);
}
}
// 更新页面方法,dep.notify执行时调用
update() {
this.get(); // 一修改数据就渲染更新
}
}
function mountComponent(vm) {
// 渲染更新页面
let updateComponent = () => {
let vnode = vm._render(); // 生成虚拟节点 vnode
vm._update(vnode); // 将vnode转为真实节点
};
// 每个组件都要调用一个渲染 watcher
new Watcher(vm, updateComponent);
}
mountComponent(vm)
发布订阅模式
基于一个事件中心,接收通知的对象是订阅者,需要 先订阅某个事件,触发事件的对象是发布者,发布者通过触发事件,通知各个订阅者。 js中事件绑定,就是发布订阅模式
发布订阅模式相比观察者模式多了个事件中心,订阅者和发布者不是直接关联的。
vue中的事件总线就是使用的发布订阅模式
// 事件总线
class Bus {
constructor() {
// 用来记录事件和监听该事件的数组
this.listeners = {};
}
// 添加指定事件的监听者
$on(eventName, handler) {
this.listeners[eventName].add(handler);
}
// 取消监听事件
$off(eventName, handler) {
this.listeners[eventName].delete(handler);
}
// 触发事件
$emit(eventName, ...args) {
this.listeners[eventName].forEach((fn) => fn(...args));
}
}
事件总线的具体使用可以查看这篇vue之事件总线
观察者模式和发布订阅模式的区别
目标和观察者之间是互相依赖的。
发布订阅模式是由统一的调度中心调用,发布者和订阅者不知道对方的存在。
vue中的观察者模式和发布订阅者模式的更多相关文章
- [JS设计模式]:观察者模式(即发布-订阅者模式)(4)
简介 观察者模式又叫发布---订阅模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知. 举一个现实生活中的例子,例如小 ...
- js中的观察者模式与发布者/订阅者模式的区别?
- 浅谈vue响应式原理及发布订阅模式和观察者模式
一.Vue响应式原理 首先要了解几个概念: 数据响应式:数据模型仅仅是普通的Javascript对象,而我们修改数据时,视图会进行更新,避免了繁琐的DOM操作,提高开发效率. 双向绑定:数据改变,视图 ...
- 观察者模式 vs 发布-订阅模式
我曾经在面试中被问道,_“观察者模式和发布订阅模式的有什么区别?” _我迅速回忆起“Head First设计模式”那本书: 发布 + 订阅 = 观察者模式 “我知道了,我知道了,别想骗我” 我微笑着回 ...
- js之观察者模式和发布订阅模式区别
观察者模式(Observer) 观察者模式指的是一个对象(Subject)维持一系列依赖于它的对象(Observer),当有关状态发生变更时 Subject 对象则通知一系列 Observer 对象进 ...
- 观察者模式(Observer)和发布-订阅者模式(Publish/Subscribe)区别
观察者模式:定义一对多的关系,让多个观察对象同时监听某一个主题对象,主题对象状态发生变化就通知所有观察者对象.所以它是由两类对像组成:Subject主题+Observer观察者.主题发布事件,观察者通 ...
- “一切都是消息”--MSF(消息服务框架)之【发布-订阅】模式
在上一篇,“一切都是消息”--MSF(消息服务框架)之[请求-响应]模式 ,我们演示了MSF实现简单的请求-响应模式的示例,今天来看看如何实现[发布-订阅]模式.简单来说,该模式的工作过程是: 客户端 ...
- “一切都是消息”--iMSF(即时消息服务框架)之【发布-订阅】模式
MSF的名字是 Message Service Framework 的简称,由于目前框架主要功能在于处理即时(immediately)消息,所以iMSF就是 immediately Message S ...
- ActiveMQ发布-订阅消息模式
一.订阅杂志我们很多人都订过杂志,其过程很简单.只要告诉邮局我们所要订的杂志名.投递的地址,付了钱就OK.出版社定期会将出版的杂志交给邮局,邮局会根据订阅的列表,将杂志送达消费者手中.这样我们就可以看 ...
- (三)ActiveMQ之发布- 订阅消息模式实现
一.概念 发布者/订阅者模型支持向一个特定的消息主题发布消息.0或多个订阅者可能对接收来自特定消息主题的消息感兴趣.在这种模型下,发布者和订阅者彼此不知道对方.这种模式好比是匿名公告板.这种模式被概括 ...
随机推荐
- Echarts xAxis、yAxis
2017年08月06日 09:10:12 数据架构师 阅读数:37641更多 所属专栏: Echarts数据可视化 版权声明:本文为博主原创文章,转载请注明来源.开发合作联系82548597@q ...
- [2009年NOIP普及组] 分数线划定
世博会志愿者的选拔工作正在A市如火如荼的进行.为了选拔最合适的人才,A市对所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试.面试分数线根据计划录取人数的150%划定,即如果计划录取m ...
- Oracle添加约束
约束 -contraint Oracle中约束类型:主键约束,唯一约束,非空约束,外键约束,check约束,下述主要是alter的方法去添加约束,也可以在建表时直接添加约束 主键约束 alter ta ...
- IE8兼容的零零碎碎
css部分 1 nth-of-type选择器 2 span:nth-of-type(1) 3 /*IE8兼容写法*/ 4 span:first-child /*选中第一个*/ 5 span:first ...
- vue后台管理系统——登录/退出功能
电商后台管理系统的功能--登录/退出功能 1. 登录业务流程 ① 在登录页面输入用户名和密码 ② 调用后台接口进行验证 ③ 通过验证之后,根据后台的响应状态跳转到项目主页 2. 登录业务的相关技术点 ...
- FastReport和RDLC报表
最近在做报表的时候第一次接触到RDLC报表,对比于之前使用的FastReport报表来说,在使用体验上个人目前感觉RDLC灵活性相对较差,尤其是表格的格式多样的时候,不易修改.RDLC应用于格式简单的 ...
- el-table 固定列错位问题
1. 问题描述:el-table使用固定列时,使用keep-alive后页面切换导致该列错位. 2. 解决方法:使用el-table的doLayout方法对表格进行重新布局 activated() { ...
- vue搭建项目iview+axios+less
项目地址:https://github.com/CinderellaStory/vue-iview-project vue搭建项目壳子已安装:iview.axios.less 已有界面:登录.左侧菜单 ...
- 在NCBI中下载SRA数据
目前,在NCBI中下载SRA数据主要有三种方式: 利用Aspera工具下载. 利用SRA Toolkit下载. 利用wget命令直接下载 第三种最为方便.其中的关键是得到下载数据的链接,即ftp的地址 ...
- 机制设计原理与应用(三)Screening
目录 3 Screening 3.1 为单个不可分割的项目定价 3.1.1 对\(\theta\)的假设 3.1.2 问题描述 3.1.3 特性 3.2 为无限可分的项目定价 3.2.1 对\(\th ...