对于宣布定阅形式想必人人并不生疏,它在异步交互中拥有很年夜的感化,能够使咱们的代码构造更加清晰易读,便于保护。
在node
中咱们能够应用 内置模块event
来实现宣布定阅形式,这篇文章咱们将深入去深造event
并演示它在咱们实践开辟中的感化,让咱们最先吧!
引入event内置模块
// 引入内置模块eventconstEventEmitter=require("events");
建立event工具
event
内置模块实质是一个构造函数,咱们需要通过new
操纵符去调用它
// 建立event工具const event = new EventEmitter();
监听事件
应用event
工具上的on
函数来界说一个监听事件,语法为:event.on(事件名,事件解决函数)
// 监听run事件event.on("run", (data) => {console.log("run事件运行,参数为:", data);});
触发事件
应用event
工具上的emit函数来触发监听的事件,语法为:event.emit(需要触发的事件名,需要给事件解决函数通报的参数)
// 触发run事件event.emit("run", "111111");
完好代码
// 引入内置模块eventconst EventEmitter = require("events");// 建立event工具const event = new EventEmitter(); // 监听run事件event.on("run", (data) => {console.log("run运行,参数为:", data);}); // 触发run事件event.emit("run", "111111");
运行效果:
❗️事件重复监听的问题
==细致:当统一事件被监听屡次时,触发事件时会同时触发这个事件的所有事件解决函数==
应用node
模拟get
申请(转发跨域数据):
const http = require("http");const https = require("https");// http以及https的区分仅在于一个是http协定一个是https协定const url = require("url"); const server = http.createServer(); server.on("request", (req, res) => {const urlObj = url.parse(req.url, true); res.writeHead(200, {"content-type": "application/json;charset=utf-8","Access-Control-Allow-Origin": "http://127.0.0.1:5500",}); switch (urlObj.pathname) {case "/api/maoyan":// 咱们界说的httpget方法:使node充当客户端去猫眼的接口获取数据httpget((data) => res.end(data)); // 细致这里break; default:res.end("404");break;}}); server.listen(3000, () => {console.log("效劳器启动啦!");}); function httpget(cb) {// 界说一个寄存数据的变量let data = "";// 因为猫眼的接口是https协定的,以是咱们需要引入https// http以及https都拥有一个get方法能够发起get申请,区分是一个是http协定,一个是https协定// http get方法第一个参数为接口所在,第二个参数为回调函数https.get("https://i.maoyan.com/api/妹妹db/movie/v3/list/hot.json?ct=%E8%A5%BF%E5%8D%8E&ci=936&channelId=4",(res) => {// http get方法获取的数据是一点点返回的,并非间接返回全部// 监听data,当稀有据返回时就会被调用res.on("data", (chunk) => {// 收罗数据data += chunk;});// 监听end,数据返回完毕后调用res.on("end", () => {cb(data); // 细致这里});});}
细致下面代码的第19行以及第49行:
httpget((data) => res.end(data)); // 细致这里
cb(data); // 细致这里
这个例子中,咱们是通过在httpget
函数中传入一个回调函数来接受httpget
函数获取到的数据,这种写法实践是不问题的,在开辟中也每一每一停止应用。
但在一些状况下,尤其是函数多层嵌套调用时(下列面的例子),这种写法就显患上不足文雅,因为它的代码构造不是很清晰,不能很直不雅的看懂其逻辑:
function user() {getUser((data) => {console.log(data);});} function getUser(cb) {// ....const id = 1;getUserInfo(cb, id);} function getUserInfo(cb, id) {// ....const name = id + "Ailjx";cb(name);}
让咱们应用内置模块event
去革新一下下面node
模拟get
申请(转发跨域数据)的案例:
const http = require("http");const https = require("https");const url = require("url");const EventEmitter = require("events");const server = http.createServer(); // 寄存event工具let event = ""; server.on("request", (req, res) => {const urlObj = url.parse(req.url, true); res.writeHead(200, {"content-type": "application/json;charset=utf-8","Access-Control-Allow-Origin": "http://127.0.0.1:5500",}); switch (urlObj.pathname) {case "/api/maoyan":event = new EventEmitter(); // 细致该地位// 监听事件event.on("resEnd", (data) => {res.end(data);});httpget();break; default:res.end("404");break;}}); server.listen(3000, () => {console.log("效劳器启动啦!");}); function httpget() {let data = "";https.get("https://i.maoyan.com/api/妹妹db/movie/v3/list/hot.json?ct=%E8%A5%BF%E5%8D%8E&ci=936&channelId=4",(res) => {res.on("data", (chunk) => {data += chunk;});res.on("end", () => {// 触发事件并通报数据event.emit("resEnd", data);});});}
运行并调用/api/maoyan
接口:
接口失常应用
细致上边代码new EventEmitter()
的地位,如果new EventEmitter()
是在外部的话,相当因而只有一个全局的event
工具,当咱们每一次调用/api/maoyan
接口时,node
都会监听一个新的resEnd
事件,这就会以致resEnd
事件被重复监听:
以是咱们才需要将建立event
工具的代码new EventEmitter()
写到接口的case
分支里,如许当咱们调用这个接口时,会建立一个新的event
工具,老的event
工具被弃用会被JS
垃圾解决机制给解决失落,如许就不会浮现resEnd
事件被重复监听的问题
网友评论