三行代码实现发布订阅,让面试官虎躯微微一震

文章介绍了发布订阅模式在软件设计中的应用,通过事件总线和PubSub的实现示例展示了如何进行事件监听和触发,以及如何通过CustomEvent进行更复杂的参数传递,强调了解耦和通信的重要性。同时,提供了兼容性垫片的代码示例,确保在不同浏览器中能正确使用CustomEvent。
摘要由CSDN通过智能技术生成

在这里插入图片描述

发布订阅模式:

定义对象间一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新
事件总线是对发布订阅模式的一种实现,也是一种集中式事件处理机制,允许不同组件之间相互通信,而不需要相互依赖,以此来解耦
应用场景:公众号消息,短信提醒等等

传统的事件总线和发布订阅的实现
事件总线
const eventBus = {
// 保存类型和回调容器
callbacks: {
// login: [fn1, fn2]
}
};

// 绑定事件
eventBus.on = function (eventName, callback) {
// 判断有该类型事件
if (this.callbacks[eventName]) {
// 推入
this.callbacks[eventName].push(callback);
} else {
// 构造该类型数组
this.callbacks[eventName] = [callback];
}
};

// 触发事件
eventBus.emit = function (eventName, data) {
// 判断有该类型事件
if (this.callbacks[eventName]?.length > 0) {
// 遍历数组里函数执行传入数据
this.callbacks[eventName].forEach(event => event(data));
}
};

eventBus.off = function (eventName) {
// 如果传入事件名
if (eventName) {
// 删除指定事件
delete this.callbacks[eventName];
} else {
// 清空
this.callbacks = {};
}
};

// 测试
eventBus.on(“login”, data => {
console.log(用户已经登陆,数据${data});
});

eventBus.on(“logout”, data => {
console.log(用户已经退出,数据${data});
});

setTimeout(() => {
eventBus.emit(“login”, “云牧”);
eventBus.emit(“logout”, “云牧”);
}, 1000);

// eventBus.off(“login”);
// eventBus.off();
复制代码
发布订阅
const PubSub = {
id: 1,
callbacks: {
// pay:{
// // token_1: fn1,
// // token_2: fn2,
// }
}
};

PubSub.subscribe = function (channel, callback) {
// 唯一的编号
let token = “token_” + this.id++;
// 判断callbacks是否存在channel
if (this.callbacks[channel]) {
// 存入
this.callbacks[channel][token] = callback;
} else {
// 构造出对象存入
this.callbacks[channel] = {
[token]: callback
};
}
return token;
};

// 订阅频道
PubSub.publish = function (channel, data) {
// 获取当前频道所有的回调 遍历执行
if (this.callbacks[channel]) {
Object.values(this.callbacks[channel]).forEach(callback => callback(data));
}
};

// 取消订阅
PubSub.unsubscribe = function (flag) {
// 没有传则全部清空
if (!flag) {
this.callbacks = {};
// 判断
} else if (typeof flag === “string”) {
// 如果包含token_
if (flag.includes(“token_”)) {
// 遍历对象找到对应token
const callbackobj = Object.values(this.callbacks).find(obj => obj.hasOwnProperty(flag));
if (callbackobj) {
delete callbackobj[flag];
}
} else {
// 删除该订阅下所有回调
delete this.callbacks[flag];
}
}
};

// 测试
const id1 = PubSub.subscribe(“pay”, data => {
console.log(“商家接受到了订单”, data);
});
const id2 = PubSub.subscribe(“pay”, data => {
console.log(“骑手接受到了订单”, data);
});
const id3 = PubSub.subscribe(“cancel”, data => {
console.log(“买家取消了订单”, data);
});

// 取消了id1,商家无法接到订单
PubSub.unsubscribe(id1);

PubSub.publish(“pay”, {
title: “鱼香肉丝”,
price: 20,
address: “xxx”
});
PubSub.publish(“cancel”, {
title: “鱼香肉丝”,
price: 20,
address: “xxx”
});

四行实现发布订阅

原理:
表面是 window,根本是 EventTarget,window、document 和元素节点都是继承于 EventTarget
XMLHttpRequest、 WebSocket 也继承于 EventTarget
继承于它,就可以实现事件中心,可以 EventTarget.addEventListener() 、 EventTarget.removeEventListener() 、EventTarget.dispatchEvent
简化三行

升级八行
上面三行实现有诸多问题,比如不能多个实例、不能传递多参数、参数从 e.detail 获取不合理等
改进如下:

自定义事件
内置事件类型

点击按钮,这是 click 事件
输入框失焦,这是 blur 事件
鼠标滚动,这是 wheel 事件

触发内置事件

element[eventType] 直接调用
new [Event] + dispatchEvent

document.createElement(“a”).click();

// 自定义事件触发
const event = new MouseEvent(“click”);

document.createElement(“a”).dispatchEvent(event);

前端快捷生成 uuid
URL.createObjectURL(new Blob([“”])).split(“/”).pop()

自定义事件三种方式

document.createEvent()(废弃)

new Event()

new CustomEvent()

document.createEvent()

const event = document.createEvent(type);

new Event

event = new Event(type, eventInit);
在这里插入图片描述

触发事件

可使用 new Event 通信,处理流程,达到解耦

开始吧

new CustomEvent
event = new Event(type, eventInit);
在这里插入图片描述
相比之前方式,它可以携带更多的参数了:

开始吧

兼容垫片(如果浏览器不支持 CustomEvent 的话):
(function () {
if (typeof CustomEvent !== “function”) {
var CustomEvent = function (event, params) {
params = params || { bubbles: false, cancelable: false, detail: undefined };

  var evt = document.createEvent("CustomEvent");

  evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);

  return evt;
};

CustomEvent.prototype = window.Event.prototype;

window.CustomEvent = CustomEvent;

}
})();

这篇就写完了,大家如果觉得好的话可以多多点赞,赠人玫瑰,手有余香。我会继续努力奉献更高质量的文章的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JackieChan_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值