JavaScript 如何实现发布订阅

你有没有过这样的经历:和朋友约好周末一起去看展览,你提前在群里“报名”,而展览主办方只要确定有足够的人参加,就会把时间、地点发在群里通知所有人,不用单独挨个跟你说。这种“一方订阅事件、一方发布通知,消息自动推给订阅者”的模式,就是今天要讲的发布订阅模式,而JavaScript里也能轻松实现它。

什么是发布订阅模式?

先把它拆成两个好懂的部分:“发布”就是有人把消息发出来,“订阅”就是有人提前等着接收这类消息。就像小区的快递通知:你(订阅者)在物业那里留了电话,物业(调度中心)收到快递(发布事件)后,会把取件码发给所有留了电话的业主,你不用天天盯着快递柜,物业也不用挨个敲门喊,两边都省心。

JavaScript 如何实现发布订阅

在代码里,它就是三个核心角色:一是“消息中心”,专门管登记谁要接收消息、谁来发消息;二是“订阅者”,负责登记自己要等的消息;三是“发布者”,把消息推给所有登记过的订阅者。

用JS写个简单的发布订阅

我们可以用一个对象当“消息中心”,用它的方法来实现订阅、发布的功能。就像给物业建一个登记本,有业主来登记(订阅),有快递来(发布),登记本就自动把消息传给所有登记的人。

先建这个“消息中心”,它需要存所有订阅的事件和对应的处理函数:

`js

// 消息中心

const eventCenter = {

// 存订阅的事件,键是事件名,值是该事件的处理函数数组

events: {},

// 订阅方法:传事件名和要执行的函数

on(eventName, handler) {

// 如果这个事件还没登记过,就新建一个数组存处理函数

if (!this.events[eventName]) {

this.events[eventName] = [];

}

// 把处理函数加入对应事件的数组里

this.events[eventName].push(handler);

},

// 发布方法:传事件名和要带的数据

emit(eventName, data) {

// 如果这个事件没有订阅者,就直接返回,不做处理

const handlers = this.events[eventName];

if (!handlers) return;

// 遍历所有订阅这个事件的处理函数,把数据传给它们执行

handlers.forEach(handler => handler(data));

}

};

`

现在用这个例子试试:假设你和朋友约了看展览,“展览确定开展”是事件,你和朋友是订阅者,分别登记接收这个事件的通知:

`js

// 订阅者1:你,收到展览消息后要做的事:查路线

eventCenter.on('展览确定开展', (data) => {

console.log(你收到通知:${data},现在查地铁路线);

});

// 订阅者2:朋友,收到消息后要做的事:调休

eventCenter.on('展览确定开展', (data) => {

console.log(朋友收到通知:${data},现在申请调休);

});

// 发布者:展览主办方,发布确定开展的消息

eventCenter.emit('展览确定开展', '本周末展览正常开展,地点在市美术馆');

`

运行这段代码,你会看到两个订阅者的处理函数都被触发了,分别输出对应的内容,就像现实里你和朋友都收到了展览通知。

解决重复订阅和取消订阅的小问题

有时候你可能会不小心给同一个事件登记两次,比如你既在群里又单独找物业登记,就会收到两次通知。我们可以加一个“取消订阅”的功能,帮你注销不用的登记:

`js

eventCenter.off(eventName, handler) {

const handlers = this.events[eventName];

if (!handlers) return;

// 过滤掉要取消的那个处理函数

this.events[eventName] = handlers.filter(h => h !== handler);

}

`

比如你后来发现朋友也会查路线,就可以把自己的订阅取消:

`js

// 先存自己的处理函数

const myHandler = (data) => console.log(你收到通知:${data},现在查地铁路线);

eventCenter.on('展览确定开展', myHandler);

// 后来取消订阅

eventCenter.off('展览确定开展', myHandler);

`

这样再发布展览消息时,你就不会重复收到通知了。

这种模式不用让发布者知道谁会接收消息,也不用让订阅者知道谁会发布,就像现实里的小区通知,两边互不打扰,代码也会更灵活,适合处理多个模块间的消息传递,比如页面里的弹窗通知、数据更新提醒等场景。

上一篇 C / C++ 从入门到进阶:掌握底层编程核心的实用知识科普