如何正确使用Node.js事件

更新日期: 2019-04-07阅读: 2.4k标签: node

事件驱动的编程变得流行之前,在程序内部进行通信的标准方法非常简单:如果一个组件想要向另外一个发送消息,只是显式地调用了那个组件上的方法。但是在 react 中用的却是事件驱动而不是调用


事件的好处

这种方法能够使组件更加分离。在我们继续写程序时,会识别整个过程中的事件,在正确的时间触发它们,并为每个事件附加一个或多个事件监听器,这使得功能扩展变得更加容易。我们可以为特定事件添加更多的 listener,而不必修改现有的侦听器或触发事件的应用程序部分。我们所谈论的是观察者模式。



设计一个事件驱动的体系结构

对事件进行识别非常重要,我们不希望最终必须从系统中删除或替换现有事件,因为这可能会迫使我们删除或修改附加到事件上的众多侦听器。我的一般原则是仅在业务逻辑单元完成执行时才考虑触发事件。

假如你想在用户注册后发送一堆不同的电子邮件。注册过程本身可能会涉及许多复杂的步骤和查询,但从商业角度来看,这只是其中的一个步骤。每个要发送的电子邮件也是单独的步骤。因此,一旦注册完成马上就发布事件是很有意义的。于是我们附加了多个监听器,每个监听器负责发送一种类型的电子邮件。

Node的异步事件驱动架构具有一些被称为“emitters”的对象。它们发出命名事件,这些事件会调用被称为“listener”的函数。发出事件的所有对象都是 EventEmitter 类的实例。使用它,我们可以创建自己的事件:


一个例子

让我们使用内置的 events 模块(我建议你查看这个文档:https://nodejs.org/api/events...)以获取对 EventEmitter 的访问权限。

const EventEmitter = require('events');

const myEmitter = new EventEmitter();

module.exports = myEmitter;

这是我们的服务器端程序的一部分,它负责接收HTTP请求,保存新用户并发出事件:

const myEmitter = require('./my_emitter');

// Perform the registration steps

// Pass the new user object as the message passed through by this event.
myEmitter.emit('user-registered', user);

附加一个监听器的单独模块:

const myEmitter = require('./my_emitter');

myEmitter.on('user-registered', (user) => {
  // Send an email or whatever.
});

将策略与实现分开是一种非常好的做法。在这种情况下,策略意味着哪些 listener 订阅了哪些事件。实现意味着 listener 自己。

const myEmitter = require('./my_emitter');
const sendEmailOnRegistration = require('./send_email_on_registration');
const someOtherListener = require('./some_other_listener');

myEmitter.on('user-registered', sendEmailOnRegistration);
myEmitter.on('user-registered', someOtherListener);
module.exports = (user) => {
  // Send a welcome email or whatever.
}

这种分离使 listener 也可以被重复使用,它可以被附加到发送相同消息的其他事件上(用户对象)。同样重要的是 当多个 listener 被附加到单个事件时,它们将按照附加的顺序同步执行。因此 someOtherListener 将在 sendEmailOnRegistration 完成执行后运行。

但是,如果你希望自己的 listener 以异步方式运行,只需用 setImmediate 包装它们的实现,如下所示:

module.exports = (user) => {
  setImmediate(() => {
    // Send a welcome email or whatever.
  });
}


让你的 Listeners 保持简洁

在写 listener 时要坚持单一责任原则。一个 listener 应该只做一件事并把事情做好。例如:要避免在 listener 中编写太多的条件并根据事件传来的数据(消息)去决定做什么。在这种情况下使用不同的事件会更加合适:

const myEmitter = require('./my_emitter');

// Perform the registration steps

// The application should react differently if the new user has been activated instantly.
if (user.activated) {
  myEmitter.emit('user-registered:activated', user);
  
} else {
  myEmitter.emit('user-registered', user);
}
const myEmitter = require('./my_emitter');
const sendEmailOnRegistration = require('./send_email_on_registration');
const someOtherListener = require('./some_other_listener');
const doSomethingEntirelyDifferent = require('./do_something_entirely_different');


myEmitter.on('user-registered', sendEmailOnRegistration);
myEmitter.on('user-registered', someOtherListener);

myEmitter.on('user-registered:activated', doSomethingEntirelyDifferent);
view raw


必要时明确分离 Listener

在前面的例子中,我们的 listener 是完全独立的函数。但是在 listener 与对象关联的情况下(这时是一种方法),必须手动将其从已订阅的事件中分离出来。否则对象将永远不会被垃圾回收,因为对象( listener )的一部分将会继续被外部对象( emitter )引用,所以存在内存泄漏的可能。

例如,如果我们正在开发一个聊天程序,并且希望当新消息到达用户进入的聊天室时,显示通知的功能应该位于该用户对象本身的内部,我们可能会这样做:

class ChatUser {
  
  displayNewMessageNotification(newMessage) {
    // Push an alert message or something.
  }
  
  // `chatroom` is an instance of EventEmitter.
  connectToChatroom(chatroom) {
    chatroom.on('message-received', this.displayNewMessageNotification);
  }

  disconnectFromChatroom(chatroom) {
    chatroom.removeListener('message-received', this.displayNewMessageNotification);
  }
}

当用户关闭他的标签或暂时断开互联网连接时,我们可能希望在服务器端发起一个回调,通知其他用户有人刚刚下线。当然在这时为脱机用户调用 displayNewMessageNotification 没有任何意义。除非我们删除它,否则它将继续被用于调用新消息。如果不这样做,除了不必要的调用之外,用户对象也会被永久地保留在内存中。因此在用户脱机时应该在服务器端回调中调用 disconnectFromChatroom。


注意事项

如果不小心,即便是松散耦合的事件驱动架构也会导致复杂性的增加,可能会导致在系统中跟踪依赖关系变得很困难。如果我们从侦听器内部发出事件,程序会特别容易出现这类问题。这可能会触发意外的事件链。


翻译:疯狂的技术
原文:https://medium.freecodecamp

 

链接: https://fly63.com/article/detial/2729

关于 Node.js 里 ES6 Modules 的一次更新说明

关于 Node.js 里 ES6 Modules 的一次更新说明,总结来说:CommonJS 与 ES6 Modules 之间的关键不同在于代码什么时候知道一个模块的结构和使用它。

用node.js开发一个可交互的命令行应用

在这个教程中,我们会开发一个命令行应用,它可以接收一个 CSV 格式的用户信息文件,教程的内容大纲:“Hello,World”,处理命令行参数,运行时的用户输入,异步网络会话,美化控制台的输出,封装成 shell 命令,JavaScript 之外

Node启动https服务器

首先你需要生成https证书,可以去付费的网站购买或者找一些免费的网站,可能会是key或者crt或者pem结尾的。不同格式之间可以通过OpenSSL转换

nodejs 异步转同步

nodej项目在微信环境开发,nodejs的异步特效,会导致请求没有完成就执行下面的代码,出现错误。经过多方查找,可以使用async模块来异步转同步,只有前一个function执行callback,下一个才会执行。

基于node服务器的大文件(G级)上传

3G的大文件分1500个2M二进度文件,通post方法发送给node服务,服务器全部接收到文件后,进组装生成你上文件。

为什么要把 JavaScript 放到服务器端上运行?

JavaScript比C的开发门槛要低,尽管服务器端JavaScript存在已经很多年了,但是后端部分一直没有市场,JavaScript在浏览器中有广泛的事件驱动方面的应用,考虑到高性能、符合事件驱动、没有历史包袱这3个主要原因,JavaScript成为了Node的实现语言。

了解node.js事件循环

node.js的第一个基本论点是I / O的性能消耗是很昂贵。因此,使用当前编程技术的最大浪费来自于等待I / O完成。有几种方法可以处理性能影响

Node.js 应用:Koa2 使用 JWT 进行鉴权

在前后端分离的开发中,通过 Restful API 进行数据交互时,如果没有对 API 进行保护,那么别人就可以很容易地获取并调用这些 API 进行操作。那么服务器端要如何进行鉴权呢?

Node.js 前端开发指南

我们经常跟Node.js打交道,即使你是一名前端开发人员 -- npm脚本,webpack配置,gulp任务,程序打包 或 运行测试等。即使你真的不需要深入理解这些任务,但有时候你会感到困惑,会因为缺少Node.js的一些核心概念而以非常奇怪的方式来编码。

happypack提升项目构建速度

运行在 Node.js 之上的 Webpack 是单线程模型的,也就是说 Webpack 需要处理的任务需要一件件挨着做,不能多个事情一起做。happypack把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!