前言
在事件驱动编程流行之前,程序内部通信的标准方法非常简单:如果一个组件想要向另一个组件发送消息,它只需显式调用该组件上的方法。然而,在react中,它是事件驱动的,而不是调用。
事件的好处
这种方法可以使组件更加分离。当我们继续编写程序时,我们会识别整个过程中的事件,在合适的时间触发它们,并为每个事件附加一个或多个事件侦听器,这样更容易扩展功能。我们可以为特定事件添加更多侦听器,而无需修改现有侦听器或触发事件的应用程序部分。我们在谈论观察者模式。
设计一个事件驱动架构
识别事件非常重要,我们不想最终不得不从系统中删除或替换现有事件,因为这可能会迫使我们删除或修改许多附加到事件的侦听器。我的一般原则是只在业务逻辑单元完成执行时才考虑触发事件。
假设你想在用户注册后发送一堆不同的邮件。注册过程本身可能涉及许多复杂的步骤和查询,但从商业角度来看,这只是其中之一。要发送的每封电子邮件也是一个单独的步骤。因此,注册完成后立即发布活动是有意义的。所以我们附加了多个监听器,每个监听器负责发送一种类型的电子邮件。
Node的异步事件驱动架构有一些被称为“发射器”的对象。它们发出命名事件,调用一个名为“监听器”的函数。发出事件的所有对象都是事件发射器类的实例。有了它,我们可以创建自己的活动:
一个例子
让我们使用内置的事件模块(我建议您查看这个文档:https://nodejs.org/api/events.)来访问事件发射器。
const event emitter=require(' events ');const MyMitter=new event emitter();module.exports=myEmitter这是我们服务器端程序的一部分,负责接收HTTP请求、保存新用户和发布事件:
const myEmitter=require('。/my _ emitter’);//执行注册步骤//按照此事件传递的消息传递新的用户对象。连接有监听器的独立模块:
const myEmitter=require('。/my _ emitter’);myEmitter.on('用户注册',(用户)={ //发送电子邮件或其他。});将政策与实施分开是一种非常好的做法。在这种情况下,策略意味着哪个侦听器订阅哪个事件。实现意味着监听器本身。
const myEmitter=require('。/my _ emitter’);const sendemailanregistration=require('。/send _ email _ on _ registration’);const someOtherListener=require('。/some _ other _ listener’);myEmitter.on('用户注册',发送电子邮件注册);myEmitter.on('用户注册',someOtherListener);模块。exports=(user)={//发送一封欢迎电子邮件或其他。}这种分离使侦听器能够被重用,并且它可以附加到发送相同消息的其他事件(用户对象)上。同样重要的是,当多个侦听器连接到一个事件时,它们将按照连接的顺序同步执行。因此,在sendEmailOnRegistration完成执行后,将运行一些其他侦听器。
但是,如果希望侦听器异步运行,只需将它们的实现包装在setImmediate中,如下所示:
module.exports=(用户)={ setImmediate(()={ //发送一封欢迎电子邮件或其他任何东西。});}让您的听众保持简单
写听者时坚持单一责任原则。一个倾听者应该只做一件事,并把它做好。例如,我们应该避免在侦听器中写入太多的条件,并根据事件的数据(消息)决定要做什么。在这种情况下,使用不同的事件更合适:
const myEmitter=require('。/my _ emitter’);//执行注册步骤//如果新用户已被立即激活,应用程序的反应应该会有所不同。if(user . activated){ my mitter . emit(' user-registered : activated ',user);} else { myemitter . emit(' user-registered ',user);} const myEmitter=require('。/my _ emitter’);const sendemailanregistration=require('。/send _ email _ on _ registration’);const someOtherListener=require('。/some _ other _ listener’);const do someingtirelydifference=require('。/do _某物_完全不同’);myEmitter.on('用户注册',发送电子邮件注册);myEmitter.on('用户注册',someOtherListener);my mitter . on(' user-registered d : activated ',do someingingtirelydifferent);必要时,查看原始数据会显式分离侦听器
在前面的例子中,我们的监听器是一个完全独立的函数。但是,当侦听器与一个对象相关联时(此时这是一个方法),它必须手动与订阅的事件分离。否则,对象永远不会被垃圾收集,因为部分侦听器会继续被外部对象引用,所以存在内存泄漏的可能。
例如,如果我们正在开发一个聊天程序,并希望当新消息到达用户输入的聊天室时,显示通知的功能应该位于用户对象本身内部,我们可以这样做:
类chat user { displayNewMessageNotification(new message){//推送警报消息什么的。} //`聊天室'是EventEmitter的一个实例。connectto chat room(chat room){ chat room . on(' message-received ',this . displaynewmessagenotification);} disconnect from chat room(chat room){ chat room . removelistener(' message-received ',this . displaynewmessagenotification);}}当用户关闭标签或暂时断开互联网连接时,我们可能希望在服务器端发起回拨,通知其他用户有人刚刚注销。当然,此时为离线用户调用displayNewMessageNotification是没有意义的。除非我们删除它,否则它将继续用于调用新消息。如果不这样做,除了不必要的调用之外,用户对象将永久保存在内存中。因此,当用户脱机时,应该在服务器端回调中调用disconnectFromChatroom。
需要注意的事项
如果不小心,即使是松散耦合的事件驱动架构也会导致复杂性增加,这可能会使跟踪系统中的依赖关系变得困难。如果我们从监听器内部发出事件,程序特别容易出现这样的问题。这可能会引发一连串意想不到的事件。
摘要
以上就是本文的全部内容。希望本文的内容对大家的学习或工作有一定的参考价值。谢谢你的支持。