当前位置: 首页 > Web前端 > JavaScript

短小精悍的发布订阅库mitt

时间:2023-03-27 17:57:32 JavaScript

介绍mitt是一个小巧美观的发布订阅库,只有几十行代码,不到200b的大小,三个重要的API。不过麻雀虽小,五脏俱全。发布-订阅模式发布-订阅模式定义了一对多的依赖关系,允许多个订阅者对象同时监听一个主题对象。当主题对象改变其状态时,它会通知所有订阅者对象,以便它们可以自动更新它们的状态。Usage有这样一个需求,小明想买100w以内的二手房,小花想买150w左右的二手房,但是房产中介告诉他们暂时没有他们想要的房子正在,中介的工作人员离开了他们。一旦有合适的房子,我们会电话通知您。这是使用发布-订阅模式的经典场景。请看下面的代码。constmitt=require("mitt");consthouseAgents=mitt();houseAgents.on("xiaoming",()=>{console.log("100w以内有房源");});houseAgents.on("xiaohua",()=>{console.log("大概有150w个listings");});过了一会儿,中介收到了150w左右的房源,立马通知了小花。houseAgents.emit("小花");源码分析mitt通过几十行代码实现了发布订阅机制。让我们剖析mitt源代码。功能手套(所有){所有=所有||对象.create(null);return{on:function(){/*somecode*/},emit:function(){/*somecode*/},off:function(){/*somecode*/},};}只有mitt库源代码中的一个mitt函数。它接收所有参数并返回一个包含三个方法的对象:on、emit和off。所有=所有||对象.create(null);mitt方法接收all参数,用于存储监听的事件。当传入的all的值为undefined、null、""、false、NaN等时,all的值默认为Object.create(null),即没有__proto__属性的对象。实际上,这里缺少类型处理。例如,mitt(true),将导致错误。constmitt=require("手套");constob=mitt(真);ob.on("a",()=>{});ob.emit("a","dd");suggestallType是object类型或者不通过。建议传入空对象或数组。constmitt=require("mitt");constob=mitt();/*或constob=mitt([]);constob=mitt({});*/接下来,让我们看看非常重要的三个方法。//...on:functionon(type,handler){(all[type]||(all[type]=[])).push(handler);}//...on接收两个参数,typetype和handler事件处理方法。方法体中只有一行非常优雅的代码。当类型存在时,将其事件处理附加到数组的后面。当类型不存在时,初始化一个空数组,存放该类型的事件处理方法。发出:函数发出(类型,evt){(所有[类型]||[]).slice().map(函数(处理程序){处理程序(evt);});(all["*"]||[]).slice().map(function(handler){handler(type,evt);});}使用on方法订阅事件,使用emit方法发布事件。在emit方法中完成了一件事。根据事件类型,遍历并调用该类型订阅的所有事件。不足通过分析mitt的源码,我们会发现mitt并没有考虑匿名函数。使用on方法时,传入的第二个参数必须是命名函数。手动实现发布订阅库classPubSub{constructor(){this.listeners=[];}sub(type,handler,always){console.log(this.listeners[type]||[]);如果(!this.listeners[type]){this.listeners[type]=[];}this.listeners[type].push({handler,always});}on(type,handler,always=true){this.sub(type,handler,always);}once(type,handler,always=false){this.sub(type,handler,always);}emit(type,evt){if(this.listeners[type]){this.listeners[type].forEach((listener)=>{listener.handler(evt);});this.listeners[type]=this.listeners[type].slice().filter((listener)=>Boolean(listener.always));}}off(type,handler){if(this.listeners[type]){this.listeners[type]=this.listeners[type].slice().filter((listener)=>listener.handler.toString()!==处理程序.toString());}}}