⚡node系列 - 观察者模式和发布订阅是有区别的

前言

NodeJS这东西是不是学过了,之后感觉又像没学到什么东西???

我最近翻到了之前学习node的笔记,又结合了一些大佬的经验,这里把node系列相关的东西串联一下,分享给小伙伴们,顺便我自己也加深一下印象。

总共分为六篇

node打怪升级系列 - 基础篇

node打怪升级系列 - Koa篇

node打怪升级系列 - 浅谈require函数

node打怪升级系列 - 手写中间件篇

node打怪升级系列 - 手写发布订阅和观察者篇

node打怪升级系列 - 手写compose(洋葱模型)

node打怪升级系列 - 手写脚手架交互式命令界面

本文重点记录下发布订阅和观察者篇里的装备

正文开始

Node中很多内置模块,比如http net都是基于发布订阅实现的

发布订阅观察者模式其实我一直觉得它就是一种东西,直到听到一大佬说这是两种设计模式

1,发布订阅

让自定义的函数,在该执行的时候执行

EventEmitterNode中做事件驱动的,EventTarget浏览器中做事件驱动的。

两个类的宿主环境是不一样的

栗子

1.1,EventEmitter

js 复制代码
const EventEmitter = require('events').EventEmitter; 
const e = new EventEmitter()
e.on('test', (data)=>{
     console.log(data) // 1s后打印'巴拉巴拉'
})

setTimeout(function() { 
    e.emit('test', '巴拉巴拉'); 
}, 1000); 

1.2,EventTarget

js 复制代码
const e = new EventTarget();
e.addEventListener('test', (data)=>{
   console.log(data) // 1s后打印'巴拉巴拉'
})

setTimeout(function() { 
    e.dispatchEvent('test', '巴拉巴拉'); 
}, 1000); 

1.3,手戳发布订阅

顺嘴一提,构造函数都是能被new

至于构造函数是什么?new的时候发生了什么?手戳一个new,以后单独出一篇讲,此处重点围绕发布订阅

此处用构造函数的方式写

js 复制代码
function EventEmitter() {
  this.events = {} // 事件对象
}

EventEmitter.prototype.on = (eventName, cb) => {
  if (!this.events) this.events = {}
  let eventList = this.events[eventName] || (this.events[eventName] = [])
  eventList.push(cb)
}

EventEmitter.prototype.emit = (eventName, ...rest) => {
  this.events[eventName] && this.events[eventName].forEach(cb => cb(...rest));
}

发布订阅的核心就是上面这行代码啦, 是不是很简洁~~~

使用如下

要点解析

我看了半天好像只有这句话可能需要再聊下

js 复制代码
let eventList = this.events[eventName] || (this.events[eventName] = [])

等于

kotlin 复制代码
this.events[eventName] =  this.events[eventName] || []

let eventList = this.events[eventName] || []

通俗的说,这是活用引用类型里的引用关系达到简写的目的

对象属于引用类型,字符串/数字/布尔/null/undefined等属于基本类型

eventListthis.events[eventName]建立了引用关系,eventList.push(xx)就等于this.events[eventName].push(xx)

js 复制代码
let a = '哈哈'
let b = '哈哈'
let c = {}
let d = {}

累了,喝口水休息会吧

2,观察者模式

此处用的方式写

js 复制代码
// 主对象/中央厨房
class Subject {
  constructor() {
    this.deps = []
  }

  attach(customer) {
    this.deps.push(customer)
  }
  // 进行广播,通知所有顾客
  notifyAll(food) {
    this.deps.forEach((customer) => {
      if (food === customer.food) customer.update()
    })
  }
}

// 观察者/顾客
class Observer {
  constructor(name, food) {
    this.name = name
    this.food = food
  }
  update() {
    console.log(`你好 ${this.name},你的${this.food}做好了`)
  }
}

使用

csharp 复制代码
// 顾客张XX来了,点了一份宫保鸡丁
let customer1 = new Observer('张XX', '宫保鸡丁')

// 顾客李XX来了,点了一份糖醋鱼
let customer2 = new Observer('李XX', '糖醋鱼')

let subject = new Subject()

// 告诉中央厨房做一份宫保鸡丁
subject.attach(customer1)

// 告诉中央厨房做一份糖醋鱼
subject.attach(customer2)

// 糖醋鱼做好了,大喇叭响起来了,李XX 你点的糖醋鱼好了
subject.notifyAll('糖醋鱼')

3,发布订阅和观察者的区别

小伙伴们应该能发现

发布订阅模式是有一个类似第三方机构处理监听事件(on)、执行事件(emit),emit和on不存在耦合

观察者模式的主对象和观察者是有依赖关系的, 存在耦合的

完结

这篇文章我尽力把我的笔记和想法放到这了,希望对小伙伴有帮助。

欢迎转载,但请注明来源。

最后,希望小伙伴们给我个免费的点赞,祝大家心想事成,平安喜乐。

相关推荐
自由生长20248 小时前
设计模式和设计原则-中高级架构思路-面向接口编程
设计模式
cz追天之路10 小时前
华为机考--- 字符串最后一个单词的长度
javascript·css·华为·less
Light6010 小时前
CSS逻辑革命:原生if()函数如何重塑我们的样式编写思维
前端·css·响应式设计·组件化开发·css if函数·声明式ui·现代css
蜡笔小嘟11 小时前
宝塔安装dify,更新最新版本--代码版
前端·ai编程·dify
ModyQyW12 小时前
HBuilderX 4.87 无法正常读取 macOS 环境配置的解决方案
前端·uni-app
bitbitDown12 小时前
我的2025年终总结
前端
五颜六色的黑12 小时前
vue3+elementPlus实现循环列表内容超出时展开收起功能
前端·javascript·vue.js
wscats13 小时前
Markdown 编辑器技术调研
前端·人工智能·markdown
EnoYao13 小时前
Markdown 编辑器技术调研
前端·javascript·人工智能
JIngJaneIL13 小时前
基于java+ vue医院管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot