Node.js的内置模块 event,利用它怎么实现发布订阅模式

 1978

对于发布订阅模式想必大家并不陌生,它在异步交互中具有很大的作用,能够使我们的代码结构更加清晰易读,便于维护。


Node.js的内置模块 event,利用它怎么实现发布订阅模式


node中我们可以使用 内置模块event 来实现发布订阅模式,这篇文章我们将深入去学习event并演示它在我们实际开发中的作用,让我们开始吧!

一、初步使用

引入event内置模块

  1. // 引入内置模块event
  2. const EventEmitter = require("events");

创建event对象

event内置模块本质是一个构造函数,我们需要通过new操作符去调用它

  1. // 创建event对象
  2. const event = new EventEmitter();

监听事件

使用event对象上的on函数来定义一个监听事件,语法为:event.on(事件名,事件处理函数)

  1. // 监听run事件
  2. event.on("run", (data) => {
  3.     console.log("run事件运行,参数为:", data);
  4. });

触发事件

使用event对象上的emit函数来触发监听的事件,语法为:event.emit(需要触发的事件名,需要给事件处理函数传递的参数)

  1. // 触发run事件
  2. event.emit("run", "111111");

完整代码

  1. // 引入内置模块event
  2. const EventEmitter = require("events");
  3. // 创建event对象
  4. const event = new EventEmitter();
  5.  
  6. // 监听run事件
  7. event.on("run", (data) => {
  8.     console.log("run运行,参数为:", data);
  9. });
  10.  
  11. // 触发run事件
  12. event.emit("run", "111111");

运行结果:


Node.js的内置模块 event,利用它怎么实现发布订阅模式


❗️ 事件重复监听的问题

==注意:当同一事件被监听多次时,触发事件时会同时触发这个事件的所有事件处理函数==


Node.js的内置模块 event,利用它怎么实现发布订阅模式


二、应用

使用node模拟get请求(转发跨域数据):

  1. const http = require("http");
  2. const https = require("https");
  3. // http和https的区别仅在于一个是http协议一个是https协议
  4. const url = require("url");
  5.  
  6. const server = http.createServer();
  7.  
  8. server.on("request", (req, res) => {
  9.     const urlObj = url.parse(req.url, true);
  10.  
  11.     res.writeHead(200, {
  12.         "content-type": "application/json;charset=utf-8",
  13.         "Access-Control-Allow-Origin": "http://127.0.0.1:5500",
  14.     });
  15.  
  16.     switch (urlObj.pathname) {
  17.         case "/api/maoyan":
  18.             // 我们定义的httpget方法:使node充当客户端去猫眼的接口获取数据
  19.             httpget((data) => res.end(data)); // 注意这里
  20.             break;
  21.  
  22.         default:
  23.             res.end("404");
  24.             break;
  25.     }
  26. });
  27.  
  28. server.listen(3000, () => {
  29.     console.log("服务器启动啦!");
  30. });
  31.  
  32. function httpget(cb) {
  33.     // 定义一个存放数据的变量
  34.     let data = "";
  35.     // 因为猫眼的接口是https协议的,所以我们需要引入https
  36.     // http和https都具有一个get方法能够发起get请求,区别是一个是http协议,一个是https协议
  37.     // http get方法第一个参数为接口地址,第二个参数为回调函数
  38.     https.get(
  39.         "https://i.maoyan.com/api/mmdb/movie/v3/list/hot.json?ct=%E8%A5%BF%E5%8D%8E&ci=936&channelId=4",
  40.         (res) => {
  41.             // http get方法获取的数据是一点点返回的,并不是直接返回全部
  42.             // 监听data,当有数据返回时就会被调用
  43.             res.on("data", (chunk) => {
  44.                 // 收集数据
  45.                 data += chunk;
  46.             });
  47.             // 监听end,数据返回完毕后调用
  48.             res.on("end", () => {
  49.                 cb(data); // 注意这里
  50.             });
  51.         }
  52.     );
  53. }

注意上面代码的第19行和第49行:

  1. httpget((data) => res.end(data)); // 注意这里
  1. cb(data); // 注意这里

这个例子中,我们是通过在httpget函数中传入一个回调函数来接收httpget函数获取到的数据,这种写法实际是没有问题的,在开发中也常常进行使用。

但在一些情况下,特别是函数多层嵌套调用时(如下面的例子),这种写法就显得不够优雅,因为它的代码结构不是很清晰,不能很直观的看懂其逻辑:

  1. function user() {
  2.     getUser((data) => {
  3.         console.log(data);
  4.     });
  5. }
  6.  
  7. function getUser(cb) {
  8.     // ....
  9.     const id = 1;
  10.     getUserInfo(cb, id);
  11. }
  12.  
  13. function getUserInfo(cb, id) {
  14.     // ....
  15.     const name = id + "Ailjx";
  16.     cb(name);
  17. }

让我们使用内置模块event去改造一下上面node模拟get请求(转发跨域数据)的案例:

  1. const http = require("http");
  2. const https = require("https");
  3. const url = require("url");
  4. const EventEmitter = require("events");
  5. const server = http.createServer();
  6.  
  7. // 存放event对象
  8. let event = "";
  9.  
  10. server.on("request", (req, res) => {
  11.     const urlObj = url.parse(req.url, true);
  12.  
  13.     res.writeHead(200, {
  14.         "content-type": "application/json;charset=utf-8",
  15.         "Access-Control-Allow-Origin": "http://127.0.0.1:5500",
  16.     });
  17.  
  18.     switch (urlObj.pathname) {
  19.         case "/api/maoyan":
  20.             event = new EventEmitter(); // 注意该位置
  21.             // 监听事件
  22.             event.on("resEnd", (data) => {
  23.                 res.end(data);
  24.             });
  25.             httpget();
  26.             break;
  27.  
  28.         default:
  29.             res.end("404");
  30.             break;
  31.     }
  32. });
  33.  
  34. server.listen(3000, () => {
  35.     console.log("服务器启动啦!");
  36. });
  37.  
  38. function httpget() {
  39.     let data = "";
  40.     https.get(
  41.         "https://i.maoyan.com/api/mmdb/movie/v3/list/hot.json?ct=%E8%A5%BF%E5%8D%8E&ci=936&channelId=4",
  42.         (res) => {
  43.             res.on("data", (chunk) => {
  44.                 data += chunk;
  45.             });
  46.             res.on("end", () => {
  47.                 // 触发事件并传递数据
  48.                 event.emit("resEnd", data);
  49.             });
  50.         }
  51.     );
  52. }

运行并调用/api/maoyan接口:


Node.js的内置模块 event,利用它怎么实现发布订阅模式


接口正常使用

注意上边代码new EventEmitter()的位置,如果new EventEmitter()是在外部的话,相当于是只有一个全局的event对象,当我们每次调用/api/maoyan接口时,node都会监听一个新的resEnd事件,这就会导致resEnd事件被重复监听


Node.js的内置模块 event,利用它怎么实现发布订阅模式


所以我们才需要将创建event对象的代码new EventEmitter()写到接口的case分支里,这样当我们调用这个接口时,会创建一个新的event对象,老的event对象被弃用会被JS垃圾处理机制给处理掉,这样就不会出现resEnd事件被重复监听的问题


本文网址:https://www.zztuku.com/detail-13127.html
站长图库 - Node.js的内置模块 event,利用它怎么实现发布订阅模式
申明:本文转载于《掘金社区》,如有侵犯,请 联系我们 删除。

评论(0)条

您还没有登录,请 登录 后发表评论!

提示:请勿发布广告垃圾评论,否则封号处理!!

    编辑推荐