Open yuanyuanbyte opened 2 years ago
本系列的主题是 JavaScript 深入系列,每期讲解一个技术要点。如果你还不了解各系列内容,文末点击查看全部文章,点我跳转到文末。
如果觉得本系列不错,欢迎 Star,你的支持是我创作分享的最大动力。
发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。
◾ 例子
比如我们很喜欢看某个公众号号的文章,但是我们不知道什么时候发布新文章,要不定时的去翻阅;这时候,我们可以关注该公众号,当有文章推送时,会有消息及时通知我们文章更新了。
上面一个看似简单的操作,其实是一个典型的发布订阅模式,公众号属于发布者,用户属于订阅者;用户将订阅公众号的事件注册到调度中心,公众号作为发布者,当有新文章发布时,公众号发布该事件到调度中心,调度中心会及时发消息告知用户。
◾ 发布/订阅模式的优点是对象之间解耦,异步编程中,可以更松耦合的代码编写;缺点是创建订阅者本身要消耗一定的时间和内存,虽然可以弱化对象之间的联系,多个发布者和订阅者嵌套一起的时候,程序难以跟踪维护。
整体的发布-订阅者模式实现思路如下:
on
fn
emit
event
off
接下来我们根据上面的思路,开始手写发布-订阅者模式 👇
我们先创建一个 Ovserver 类:
+ class Observer { + + }
在 Observer 类里,需要添加一个构造函数:
class Observer { + constructor(){ + + } }
还需要添加三个方法,也就是我们前面讲到的on、emit和off方法,为了让这个方法长得更像 Vue,我们在这几个方法前面都加上$,即:
$
$on
$off
$emit
class Observer { constructor() { } + // 向消息队列添加内容 `$on` + $on(){} + // 删除消息队列里的内容 `$off` + $off(){} + // 触发消息队列里的内容 `$emit` + $emit(){} }
方法具体的内容我们放一放,先来创建一个订阅者(发布者),
使用构造函数创建一个实例:
class Observer { constructor() { } // 向消息队列添加内容 `$on` $on(){} // 删除消息队列里的内容 `$off` $off(){} // 触发消息队列里的内容 `$emit` $emit(){} } + // 使用构造函数创建一个实例 + const person1 = new Observer()
接着,我们向这个person1委托一些内容,也就是说调用person1的$ON方法:
person1
$ON
class Observer { constructor() { } // 向消息队列添加内容 `$on` $on() {} // 删除消息队列里的内容 `$off` $off() {} // 触发消息队列里的内容 `$emit` $emit() {} } // 使用构造函数创建一个实例 const person1 = new Observer(); + // 向这个`person1`委托一些内容,调用`person1 `的`$ON`方法 + person1.$on()
既然要委托一些内容,那 事件名 就必不可少,事件触发的时候也需要一个 回调函数
举个例子,我们写几个事件,比如:
class Observer { constructor() { } // 向消息队列添加内容 `$on` $on() {} // 删除消息队列里的内容 `$off` $off() {} // 触发消息队列里的内容 `$emit` $emit() {} } // 使用构造函数创建一个实例 const person1 = new Observer(); // 向这个`person1`委托一些内容,调用`person1 `的`$ON`方法 person1.$on() + function handlerA() { + console.log('handlerA'); + } + + function handlerB() { + console.log('handlerB'); + } + + function handlerC() { + console.log('handlerC'); }
我们现在拜托 person1 监听一下 买红宝石 ,红宝石到了之后,执行回调函数 handlerA 和 handlerB,就可以这样写:
买红宝石
handlerA
handlerB
class Observer { constructor() { } // 向消息队列添加内容 `$on` $on() {} // 删除消息队列里的内容 `$off` $off() {} // 触发消息队列里的内容 `$emit` $emit() {} } // 使用构造函数创建一个实例 const person1 = new Observer(); // 向这个`person1`委托一些内容,调用`person1 `的`$ON`方法 + person1.$on('买红宝石', handlerA) + person1.$on('买红宝石', handlerB) function handlerA() { console.log('handlerA'); } function handlerB() { console.log('handlerB'); } function handlerC() { console.log('handlerC'); }
再拜托 person1 监听一下 买奶茶 ,奶茶到了之后,执行回调函数 handlerC :
买奶茶
handlerC
class Observer { constructor() { } // 向消息队列添加内容 `$on` $on() {} // 删除消息队列里的内容 `$off` $off() {} // 触发消息队列里的内容 `$emit` $emit() {} } // 使用构造函数创建一个实例 const person1 = new Observer(); // 向这个`person1`委托一些内容,调用`person1 `的`$ON`方法 person1.$on('买红宝石', handlerA) person1.$on('买红宝石', handlerB) + person1.$on('买奶茶', handlerC) function handlerA() { console.log('handlerA'); } function handlerB() { console.log('handlerB'); } function handlerC() { console.log('handlerC'); }
到这里我们就需要前面讲到的 缓存列表(消息队列),也就是调度中心了。
给Observer类添加 缓存列表:
Observer
class Observer { constructor() { + this.message = {} // 消息队列 } // 向消息队列添加内容 `$on` $on() {} // 删除消息队列里的内容 `$off` $off() {} // 触发消息队列里的内容 `$emit` $emit() {} } // 使用构造函数创建一个实例 const person1 = new Observer();
这个缓存列表 message 对象的功能如下:
message
向 person1 委托一个buy类型的内容,完成之后执行回调函数 handlerA 和 handlerB
buy
class Observer { constructor() { this.message = {} // 消息队列 } // 向消息队列添加内容 `$on` $on() {} // 删除消息队列里的内容 `$off` $off() {} // 触发消息队列里的内容 `$emit` $emit() {} } // 使用构造函数创建一个实例 const person1 = new Observer(); + person1.$on('buy',handlerA); + person1.$on('buy',handlerB); function handlerA() { console.log('handlerA'); } function handlerB() { console.log('handlerB'); } function handlerC() { console.log('handlerC'); }
我们希望通过$on向消息队列添加上面内容后,就相当对给message对象添加了一个buy属性,这个属性值为[handlerA, handlerB],相当于下面的效果:
[handlerA, handlerB]
class Observer { constructor() { this.message = { + buy: [handlerA, handlerB] } } // 向消息队列添加内容 `$on` $on() {} // 删除消息队列里的内容 `$off` $off() {} // 触发消息队列里的内容 `$emit` $emit() {} }
需求明确后,下面着手 写 $on 函数 👇👇👇
回顾一行代码:
person1.$on('buy',handlerA);
很明显我们给$on方法传入了两个参数:
type
callback
class Observer { constructor() { this.message = {} // 消息队列 } + /** + * `$on` 向消息队列添加内容 + * @param {*} type 事件名 (事件类型) + * @param {*} callback 回调函数 + */ + $on(type, callback) {} // 删除消息队列里的内容 `$off` $off() {} // 触发消息队列里的内容 `$emit` $emit() {} } // 使用构造函数创建一个实例 const person1 = new Observer(); person1.$on('buy', handlerA); person1.$on('buy', handlerB);
我们初步设想一下如何向消息队列添加内容,消息队列是一个对象,可以通过下面的方法添加事件内容:
class Observer { constructor() { this.message = {} // 消息队列 } /** * `$on` 向消息队列添加内容 * @param {*} type 事件名 (事件类型) * @param {*} callback 回调函数 */ $on(type, callback) { + this.message[type] = callback; } // 删除消息队列里的内容 `$off` $off() {} // 触发消息队列里的内容 `$emit` $emit() {} }
但通过前文我们知道消息队列中每个属性值都是 数组:
this.message = { buy: [handlerA, handlerB] }
即每个事件类型对应多个消息 (回调函数),这样的话我们就要为每个事件类型创建一个数组,具体写法:
代码实现如下:
class Observer { constructor() { this.message = {} // 消息队列 } /** * `$on` 向消息队列添加内容 * @param {*} type 事件名 (事件类型) * @param {*} callback 回调函数 */ $on(type, callback) { + // 判断有没有这个属性(事件类型) + if (!this.message[type]) { + // 如果没有这个属性,就初始化一个空的数组 + this.message[type] = []; + } + // 如果有这个属性,就往他的后面push一个新的callback + this.message[type].push(callback) } // 删除消息队列里的内容 `$off` $off() {} // 触发消息队列里的内容 `$emit` $emit() {} }
$on 的代码实现如上所示,我们加上用例并引入到一个html文件中测试一下:
Observe.js
class Observer { constructor() { this.message = {} // 消息队列 } /** * `$on` 向消息队列添加内容 * @param {*} type 事件名 (事件类型) * @param {*} callback 回调函数 */ $on(type, callback) { // 判断有没有这个属性(事件类型) if (!this.message[type]) { // 如果没有这个属性,就初始化一个空的数组 this.message[type] = []; } // 如果有这个属性,就往他的后面push一个新的callback this.message[type].push(callback) } // 删除消息队列里的内容 `$off` $off() {} // 触发消息队列里的内容 `$emit` $emit() {} } function handlerA() { console.log('handlerA'); } function handlerB() { console.log('handlerB'); } function handlerC() { console.log('handlerC'); } // 使用构造函数创建一个实例 const person1 = new Observer(); person1.$on('buy', handlerA); person1.$on('buy', handlerB); console.log('person1 :>> ', person1);
Oberver.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 引入Observe.js文件 --> <script src="../JS/Observer.js"></script> </body> </html>
输出结果:
打印出的 person1 是 Oberver 类型的,里面有一个message,也就是咱定义的消息队列;这个message里有我们添加的buy类型的事件,这个buy事件有两个消息:[handlerA,handlerB],测试通过 👏👏👏
[handlerA,handlerB]
接下来,我们来实现 $off 方法
$off 方法用来删除消息队列里的内容
$off 方法有两种写法:
person1.$off("buy")
person1.$off("buy",handlerA)
和$on方法一样,$off方法也需要type和callback这两个方法:
class Observer { constructor() { this.message = {} // 消息队列 } /** * `$on` 向消息队列添加内容 * @param {*} type 事件名 (事件类型) * @param {*} callback 回调函数 */ $on(type, callback) { // 判断有没有这个属性(事件类型) if (!this.message[type]) { // 如果没有这个属性,就初始化一个空的数组 this.message[type] = []; } // 如果有这个属性,就往他的后面push一个新的callback this.message[type].push(callback) } + /** + * $off 删除消息队列里的内容 + * @param {*} type 事件名 (事件类型) + * @param {*} callback 回调函数 + */ + $off(type, callback) {} // 触发消息队列里的内容 `$emit` $emit() {} }
$off方法的实现步骤如下:
class Observer { constructor() { this.message = {} // 消息队列 } /** * `$on` 向消息队列添加内容 * @param {*} type 事件名 (事件类型) * @param {*} callback 回调函数 */ $on(type, callback) { // 判断有没有这个属性(事件类型) if (!this.message[type]) { // 如果没有这个属性,就初始化一个空的数组 this.message[type] = []; } // 如果有这个属性,就往他的后面push一个新的callback this.message[type].push(callback); } /** * $off 删除消息队列里的内容 * @param {*} type 事件名 (事件类型) * @param {*} callback 回调函数 */ $off(type, callback) { + // 判断是否有订阅,即消息队列里是否有type这个类型的事件,没有的话就直接return + if (!this.message[type]) return; + // 判断是否有callback这个参数 + if (!callback) { + // 如果没有callback,就删掉整个事件ß + this.message[type] = undefined; + } + // 如果有callback,就仅仅删掉callback这个消息(过滤掉这个消息方法) + this.message[type] = this.message[type].filter((item) => item !== callback); } // 触发消息队列里的内容 `$emit` $emit() {} }
以上就是$off的实现,我们先来测试一下:
class Observer { ... } function handlerA() { console.log('handlerA'); } function handlerB() { console.log('handlerB'); } function handlerC() { console.log('handlerC'); } // 使用构造函数创建一个实例 const person1 = new Observer(); person1.$on('buy', handlerA); person1.$on('buy', handlerB); person1.$on('buy', handlerC); console.log('person1 :>> ', person1);
● 测试删除单个消息,使用$off 删除 handlerC 消息
class Observer { ... } function handlerA() { console.log('handlerA'); } function handlerB() { console.log('handlerB'); } function handlerC() { console.log('handlerC'); } // 使用构造函数创建一个实例 const person1 = new Observer(); person1.$on('buy', handlerA); person1.$on('buy', handlerB); person1.$on('buy', handlerC); console.log('person1 :>> ', person1); + // 删除 handlerC 消息 + person1.$off('buy',handlerC); + console.log('person1 :>> ', person1);
测试通过 🥳🥳🥳
● 测试删除整个事件类型,使用$off 删除整个 buy 事件
class Observer { ... } function handlerA() { console.log('handlerA'); } function handlerB() { console.log('handlerB'); } function handlerC() { console.log('handlerC'); } // 使用构造函数创建一个实例 const person1 = new Observer(); person1.$on('buy', handlerA); person1.$on('buy', handlerB); person1.$on('buy', handlerC); console.log('person1 :>> ', person1); // 删除 handlerC 消息 person1.$off('buy',handlerC); console.log('person1 :>> ', person1); + // 删除 buy 事件 + person1.$off('buy'); + console.log('person1 :>> ', person1);
Perfect!!!测试通过 ✅
这样以来 $off 的两个功能我们就已经成功实现 👏👏👏
● 关于 $off 的实现,这里讲一个小细节 👇
javascript 删除对象的某个属性 有两种方法:
obj.key = undefined;
obj[key] = undefined;
这两种方法的区别:
1. delete 操作符会从某个对象上移除指定属性,但它的工作量比其“替代”设置也就是 object[key] = undefined 多的多的多。
object[key] = undefined
并且该方法有诸多限制,比如,以下情况需要重点考虑:
如果你试图删除的属性不存在,那么delete将不会起任何作用,但仍会返回true
如果对象的原型链上有一个与待删除属性同名的属性,那么删除属性之后,对象会使用原型链上的那个属性(也就是说,delete操作只会在自身的属性上起作用)
任何使用 var 声明的属性不能从全局作用域或函数的作用域中删除。
var
任何用let或const 声明的属性不能够从它被声明的作用域中删除。
let
const
不可设置的(Non-configurable)属性不能被移除。这意味着像Math, Array, Object内置对象的属性以及使用Object.defineProperty()方法设置为不可设置的属性不能被删除。
Math
Array
Object
Object.defineProperty()
2. obj[key] = undefined; 这个选择不是这个问题的正确答案,因为只是把某个属性替换为undefined,属性本身还在。但是,如果你小心使用它,你可以大大加快一些算法。
undefined
好了,回到正题 🙌
接下来我们开始实现第三个方法 $emit 🧗♀️
$emit 用来触发消息队列里的内容:
该方法需要传入一个 type 参数,用来确定触发哪一个事件;
主要流程就是对这个type事件做一个轮询 (for循环),挨个执行每一个消息的回调函数callback就👌了。
具体代码实现如下:
class Observer { constructor() { this.message = {} // 消息队列 } /** * `$on` 向消息队列添加内容 * @param {*} type 事件名 (事件类型) * @param {*} callback 回调函数 */ $on(type, callback) { // 判断有没有这个属性(事件类型) if (!this.message[type]) { // 如果没有这个属性,就初始化一个空的数组 this.message[type] = []; } // 如果有这个属性,就往他的后面push一个新的callback this.message[type].push(callback); } /** * $off 删除消息队列里的内容 * @param {*} type 事件名 (事件类型) * @param {*} callback 回调函数 */ $off(type, callback) { // 判断是否有订阅,即消息队列里是否有type这个类型的事件,没有的话就直接return if (!this.message[type]) return; // 判断是否有callback这个参数 if (!callback) { // 如果没有callback,就删掉整个事件 this.message[type] = undefined; return; } // 如果有callback,就仅仅删掉callback这个消息(过滤掉这个消息方法) this.message[type] = this.message[type].filter((item) => item !== callback); } + /** + * $emit 触发消息队列里的内容 + * @param {*} type 事件名 (事件类型) + */ + $emit(type) { + // 判断是否有订阅 + if(!this.message[type]) return; + // 如果有订阅,就对这个`type`事件做一个轮询 (for循环) + this.message[type].forEach(item => { + // 挨个执行每一个消息的回调函数callback + item() + }); + } }
打完收工🏌️♀️
来测试一下吧~
class Observer { ... } function handlerA() { console.log('buy handlerA'); } function handlerB() { console.log('buy handlerB'); } function handlerC() { console.log('buy handlerC'); } // 使用构造函数创建一个实例 const person1 = new Observer(); + person1.$on('buy', handlerA); + person1.$on('buy', handlerB); + person1.$on('buy', handlerC); console.log('person1 :>> ', person1); + // 触发 buy 事件 + person1.$emit('buy')
测试通过 👏👏👏
本篇文章实现了最简单的发布订阅者模式,他的核心内容只有四个:
发布订阅者模式完整代码实现:
完整版的代码较长,这里看着如果不方便的可以去我的GitHub上看,我专门维护了一个 前端 BLOG 的仓库:https://github.com/yuanyuanbyte/Blog
class Observer { constructor() { this.message = {} // 消息队列 } /** * `$on` 向消息队列添加内容 * @param {*} type 事件名 (事件类型) * @param {*} callback 回调函数 */ $on(type, callback) { // 判断有没有这个属性(事件类型) if (!this.message[type]) { // 如果没有这个属性,就初始化一个空的数组 this.message[type] = []; } // 如果有这个属性,就往他的后面push一个新的callback this.message[type].push(callback); } /** * $off 删除消息队列里的内容 * @param {*} type 事件名 (事件类型) * @param {*} callback 回调函数 */ $off(type, callback) { // 判断是否有订阅,即消息队列里是否有type这个类型的事件,没有的话就直接return if (!this.message[type]) return; // 判断是否有callback这个参数 if (!callback) { // 如果没有callback,就删掉整个事件 this.message[type] = undefined; return; } // 如果有callback,就仅仅删掉callback这个消息(过滤掉这个消息方法) this.message[type] = this.message[type].filter((item) => item !== callback); } /** * $emit 触发消息队列里的内容 * @param {*} type 事件名 (事件类型) */ $emit(type) { // 判断是否有订阅 if(!this.message[type]) return; // 如果有订阅,就对这个`type`事件做一个轮询 (for循环) this.message[type].forEach(item => { // 挨个执行每一个消息的回调函数callback item() }); } }
查看原文
查看全部文章
各系列文章汇总:https://github.com/yuanyuanbyte/Blog
我是圆圆,一名深耕于前端开发的攻城狮。
// 判断是否有callback这个参数
你好,这里应该还需要一个 return 吧
本系列的主题是 JavaScript 深入系列,每期讲解一个技术要点。如果你还不了解各系列内容,文末点击查看全部文章,点我跳转到文末。
如果觉得本系列不错,欢迎 Star,你的支持是我创作分享的最大动力。
前言
发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。
◾ 例子
比如我们很喜欢看某个公众号号的文章,但是我们不知道什么时候发布新文章,要不定时的去翻阅;这时候,我们可以关注该公众号,当有文章推送时,会有消息及时通知我们文章更新了。
上面一个看似简单的操作,其实是一个典型的发布订阅模式,公众号属于发布者,用户属于订阅者;用户将订阅公众号的事件注册到调度中心,公众号作为发布者,当有新文章发布时,公众号发布该事件到调度中心,调度中心会及时发消息告知用户。
◾ 发布/订阅模式的优点是对象之间解耦,异步编程中,可以更松耦合的代码编写;缺点是创建订阅者本身要消耗一定的时间和内存,虽然可以弱化对象之间的联系,多个发布者和订阅者嵌套一起的时候,程序难以跟踪维护。
手写实现发布-订阅者模式
整体的发布-订阅者模式实现思路如下:
on
方法 - 用来把函数fn
添加到缓存列表(订阅者注册事件到调度中心)emit
方法 - 取到event
事件类型,根据event
值去执行对应缓存列表中的函数(发布者发布事件到调度中心,调度中心处理代码)off
方法 - 可以根据event
事件类型取消订阅(取消订阅)接下来我们根据上面的思路,开始手写发布-订阅者模式 👇
1. 创建一个 Observer 类
我们先创建一个 Ovserver 类:
在 Observer 类里,需要添加一个构造函数:
2. 添加三个核心方法
还需要添加三个方法,也就是我们前面讲到的
on
、emit
和off
方法,为了让这个方法长得更像 Vue,我们在这几个方法前面都加上$
,即:$on
$off
$emit
方法具体的内容我们放一放,先来创建一个订阅者(发布者),
使用构造函数创建一个实例:
接着,我们向这个
person1
委托一些内容,也就是说调用person1
的$ON
方法:既然要委托一些内容,那 事件名 就必不可少,事件触发的时候也需要一个 回调函数
举个例子,我们写几个事件,比如:
我们现在拜托
person1
监听一下买红宝石
,红宝石到了之后,执行回调函数handlerA
和handlerB
,就可以这样写:再拜托
person1
监听一下买奶茶
,奶茶到了之后,执行回调函数handlerC
:3. 设置缓存列表
到这里我们就需要前面讲到的 缓存列表(消息队列),也就是调度中心了。
给
Observer
类添加 缓存列表:这个缓存列表
message
对象的功能如下:向
person1
委托一个buy
类型的内容,完成之后执行回调函数handlerA
和handlerB
我们希望通过
$on
向消息队列添加上面内容后,就相当对给message
对象添加了一个buy
属性,这个属性值为[handlerA, handlerB]
,相当于下面的效果:需求明确后,下面着手 写
$on
函数 👇👇👇4. 实现 $on 方法
回顾一行代码:
很明显我们给
$on
方法传入了两个参数:type
:事件名 (事件类型)callback
:回调函数我们初步设想一下如何向消息队列添加内容,消息队列是一个对象,可以通过下面的方法添加事件内容:
但通过前文我们知道消息队列中每个属性值都是 数组:
即每个事件类型对应多个消息 (回调函数),这样的话我们就要为每个事件类型创建一个数组,具体写法:
代码实现如下:
$on
的代码实现如上所示,我们加上用例并引入到一个html文件中测试一下:Observe.js
Oberver.html
输出结果:
打印出的 person1 是 Oberver 类型的,里面有一个message,也就是咱定义的消息队列;这个message里有我们添加的
buy
类型的事件,这个buy
事件有两个消息:[handlerA,handlerB]
,测试通过 👏👏👏接下来,我们来实现
$off
方法5. 实现 $off 方法
$off
方法用来删除消息队列里的内容$off
方法有两种写法:person1.$off("buy")
- 删除整个buy
事件类型person1.$off("buy",handlerA)
- 只删除handlerA
消息,保留buy
事件列表里的其他消息和
$on
方法一样,$off
方法也需要type
和callback
这两个方法:$off
方法的实现步骤如下:代码实现如下:
以上就是
$off
的实现,我们先来测试一下:输出结果:
● 测试删除单个消息,使用
$off
删除 handlerC 消息输出结果:
测试通过 🥳🥳🥳
● 测试删除整个事件类型,使用
$off
删除整个 buy 事件输出结果:
Perfect!!!测试通过 ✅
这样以来
$off
的两个功能我们就已经成功实现 👏👏👏● 关于
$off
的实现,这里讲一个小细节 👇javascript 删除对象的某个属性 有两种方法:
obj.key = undefined;
(等同于obj[key] = undefined;
)这两种方法的区别:
1. delete 操作符会从某个对象上移除指定属性,但它的工作量比其“替代”设置也就是
object[key] = undefined
多的多的多。并且该方法有诸多限制,比如,以下情况需要重点考虑:
如果你试图删除的属性不存在,那么delete将不会起任何作用,但仍会返回true
如果对象的原型链上有一个与待删除属性同名的属性,那么删除属性之后,对象会使用原型链上的那个属性(也就是说,delete操作只会在自身的属性上起作用)
任何使用
var
声明的属性不能从全局作用域或函数的作用域中删除。任何用
let
或const
声明的属性不能够从它被声明的作用域中删除。不可设置的(Non-configurable)属性不能被移除。这意味着像
Math
,Array
,Object
内置对象的属性以及使用Object.defineProperty()
方法设置为不可设置的属性不能被删除。2.
obj[key] = undefined;
这个选择不是这个问题的正确答案,因为只是把某个属性替换为undefined
,属性本身还在。但是,如果你小心使用它,你可以大大加快一些算法。好了,回到正题 🙌
接下来我们开始实现第三个方法
$emit
🧗♀️6. 实现
$emit
方法$emit
用来触发消息队列里的内容:该方法需要传入一个
type
参数,用来确定触发哪一个事件;主要流程就是对这个
type
事件做一个轮询 (for循环),挨个执行每一个消息的回调函数callback就👌了。具体代码实现如下:
打完收工🏌️♀️
来测试一下吧~
输出结果:
测试通过 👏👏👏
完整代码
本篇文章实现了最简单的发布订阅者模式,他的核心内容只有四个:
message
$on
$off
$emit
发布订阅者模式完整代码实现:
完整版的代码较长,这里看着如果不方便的可以去我的GitHub上看,我专门维护了一个 前端 BLOG 的仓库:https://github.com/yuanyuanbyte/Blog
查看原文
查看全部文章
博文系列目录
交流
各系列文章汇总:https://github.com/yuanyuanbyte/Blog
我是圆圆,一名深耕于前端开发的攻城狮。