发布订阅者模式(观察者模式)
2020-12-18 本文已影响0人
Raral
概念: 其定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。

举例说明:
- 假如用户A订阅了 某一个公众号G,那么当公众号G推送消息的时候,用户A就会收到相关的推送,点开可以查看推送的消息内容。
- 但是公众号G并不关心订阅的它的是男人、女人还是二哈,它只负责发布自己的主体,只要是订阅公众号的用户均会收到该消息。
- 作为用户A,不需要时刻打开手机查看公众号G是否有推动消息,因为在公众号推送消息的那一刻,用户A就会收到相关推送。
- 当然了,用户A如果不想继续关注公众号G,那么可以取消关注,取关以后,公众号G再推送消息,A就无法收到了
发布-订阅模式场景
webpack中 tapable
tapable 是一个类似于 Node.js 中的 EventEmitter的库,是一个发布订阅者模式,但更专注于自定义事件的触发和处理。webpack 通过 tapable 将实现与流程解耦,所有具体实现通过插件的形式存在。
- 同步的钩子
- SyncHook
/**
* tabaple 是 基于事件流的框架,发布订阅者模式
*
* 1\. 同步的 同步钩子构造函数
* SyncHook 依赖的回调函数 执行时没有任何关系 独立执行
* SyncBailHook 依赖的回调函数 执行顺序必须有保证,执行下一个必须保证上一个正确
* SyncWaterfallHook 依赖的回调函数 执行下一个回调函数的参数是 上一个回调函数的返回值
* SyncLoopHook 依赖的回调函数 可能某一个函数需要执行多次后才执行下一个函数
*
* 2\. 异步的
*
*/
class SyncHook {
constructor(args) {
this.tasks = [];// 存放呆要执行的任务
}
tap(name,callback) {// 注册新的任务 存放到tasks中
this.tasks.push(callback)
}
call(...args) {// 执行有关联的任务 tasks
this.tasks.forEach(callback => {
callback&&callback(...args);
})
}
}
let hook = new SyncHook(["name"]);
hook.tap("react", function(name) {
console.log("react", name)
})
hook.tap("node", function(name) {
console.log("node", name)
})
hook.call("xxx")
//react xxx
//node xxx
- SyncBailHook
/**
* tabaple 是 基于事件流的框架,发布订阅者模式
*
* 1\. 同步的 同步钩子构造函数
* SyncHook 依赖的回调函数 执行时没有任何关系 独立执行
* SyncBailHook 依赖的回调函数 执行顺序必须有保证,执行下一个必须保证上一个正确
* SyncWaterfallHook 依赖的回调函数 执行下一个回调函数的参数是 上一个回调函数的返回值
* SyncLoopHook
*
* 2\. 异步的
*
*/
class SyncBailHook {
constructor(args) {
this.tasks = [];// 存放呆要执行的任务
}
tap(name,callback) {// 注册新的任务 存放到tasks中
this.tasks.push(callback)
}
call(...args) {// 执行有关联的任务 tasks
let ret,index = 0;
do {
ret = this.tasks[ index ++ ](...args);
} while (ret === undefined && index < this.tasks.length);
}
}
let hook = new SyncBailHook(["name"]);
hook.tap("react", function(name) {
console.log("react", name)
return "像停止" //下一个任务不执行
})
hook.tap("node", function(name) {
console.log("node", name)
})
hook.call("xxx")
//react xxx
//node xxx
- SyncWaterfallHook
/**
* tabaple 是 基于事件流的框架,发布订阅者模式
*
* 1\. 同步的 同步钩子构造函数
* SyncHook 依赖的回调函数 执行时没有任何关系 独立执行
* SyncBailHook 依赖的回调函数 执行顺序必须有保证,执行下一个必须保证上一个正确
* SyncWaterfallHook 依赖的回调函数 执行下一个回调函数的参数是 上一个回调函数的返回值
* SyncLoopHook
*
* 2\. 异步的
*
*/
class SyncWaterfallHook {
constructor(args) {
this.tasks = [];// 存放呆要执行的任务
}
tap(name,callback) {// 注册新的任务 存放到tasks中
this.tasks.push(callback)
}
call(...args) {// 执行有关联的任务 tasks
let [first, ...others] = this.tasks;
let ret = first(...args);
others.reduce((acc,cur) => {
return cur(acc)
}, ret)
}
}
let hook = new SyncWaterfallHook(["name"]);
hook.tap("react", function(name) {
console.log("react", name)
return "react"
})
hook.tap("node", function(data) {
console.log("node", data)
return data
})
hook.tap("vue", function(data) {
console.log("vue", data)
})
hook.call("xxx")
//react xxx
//node xxx
- SyncWaterfallHook
/**
* tabaple 是 基于事件流的框架,发布订阅者模式
*
* 1\. 同步的 同步钩子构造函数
* SyncHook 依赖的回调函数 执行时没有任何关系 独立执行
* SyncBailHook 依赖的回调函数 执行顺序必须有保证,执行下一个必须保证上一个正确
* SyncWaterfallHook 依赖的回调函数 执行下一个回调函数的参数是 上一个回调函数的返回值
* SyncLoopHook
*
* 2\. 异步的
*
*/
class SyncWaterfallHook {
constructor(args) {
this.tasks = [];// 存放呆要执行的任务
}
tap(name,callback) {// 注册新的任务 存放到tasks中
this.tasks.push(callback)
}
call(...args) {// 执行有关联的任务 tasks
let [first, ...others] = this.tasks;
let ret = first(...args);
others.reduce((acc,cur) => {
return cur(acc)
}, ret)
}
}
let hook = new SyncWaterfallHook(["name"]);
hook.tap("react", function(name) {
console.log("react", name)
return "react"
})
hook.tap("node", function(data) {
console.log("node", data)
return data
})
hook.tap("vue", function(data) {
console.log("vue", data)
})
hook.call("xxx")
//react xxx
//node xxx
- SyncLoopHook
/**
* tabaple 是 基于事件流的框架,发布订阅者模式
*
* 1\. 同步的 同步钩子构造函数
* SyncHook 依赖的回调函数 执行时没有任何关系 独立执行
* SyncBailHook 依赖的回调函数 执行顺序必须有保证,执行下一个必须保证上一个正确
* SyncWaterfallHook 依赖的回调函数 执行下一个回调函数的参数是 上一个回调函数的返回值
* SyncLoopHook 依赖的回调函数 中可能像让某一个函数执行 多次,再执行下一个回调函数
*
* 2\. 异步的
*
*/
class SyncLoopHook {
constructor(args) {
this.tasks = [];// 存放呆要执行的任务
}
tap(name,callback) {// 注册新的任务 存放到tasks中
this.tasks.push(callback)
}
call(...args) {// 执行有关联的任务 tasks
this.tasks.forEach(task => {
let ret;
do {
ret = task(...args);
} while (ret != undefined);
})
}
}
let hook = new SyncLoopHook(["name"]);
let count = 0;
hook.tap("react", function(name) {
console.log("react", name)
return ++count == 3? undefined : "继续学react"
})
hook.tap("node", function(data) {
console.log("node", data)
return data
})
hook.tap("vue", function(data) {
console.log("vue", data)
})
hook.call("xxx")
//react xxx
//node xxx
发布订阅模式基本原理
class Observer {
constructor() {
//存放 事件对应的信息
/**
* {
* eventName1: [
* callback1,callback2
* ],
* eventName2: [
* callback_a, callback_b
* ]
*
* }
*/
this.events = {} //事件中心
}
publish(eventName, ...args) { //发布 => 调用事件中心对应的的函数
if(this.events[eventName]) {
this.events[eventName].forEach(cb => cb.apply(this,args))
}
}
subscribe(eventName,callback) {// 订阅 => 向事件中心中添加对应的事件
if(this.events[eventName]) {
this.events[eventName].push(callback);
}else {
this.events[eventName] = [ callback ]
}
}
unSubscribe(eventName, callback) { //取消订阅 => 把对应事件名称对应的函数中
if(events[eventName]) {
events[eventName] = events[eventName].filter(cb != callback);
}
}
}
let observer = new Observer();
//测试
//先订阅
observer.subscribe("eventOne", function() {
console.log("我是eventOne的回调函数1")
})
observer.subscribe("eventOne", function() {
console.log("我是eventOne的回调函数2")
})
observer.subscribe("eventOne", function() {
console.log("我是eventOne的回调函数3")
})
observer.subscribe("eventTwo", function() {
console.log("我是eventTwo的回调函数1")
})
//然后发布指定事件,调用相关的回调函数
observer.publish("eventOne");
//我是eventOne的回调函数1
//我是eventOne的回调函数2
//我是eventOne的回调函数3