⚡node系列 - 观察者和发布订阅原来不一样啊

568 阅读3分钟

前言

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

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

总共分为六篇

node打怪升级系列 - 基础篇

node打怪升级系列 - Koa篇

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

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

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

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

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

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

image.png

正文开始

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

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

1,发布订阅

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

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

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

栗子

1.1,EventEmitter

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

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

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

1.3,手戳发布订阅

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

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

此处用构造函数的方式写

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));
}

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

使用如下

image.png

要点解析

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

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

等于

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

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

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

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

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

let a = '哈哈'
let b = '哈哈'
let c = {}
let d = {}

image.png

累了,喝口水休息会吧

image.png

2,观察者模式

此处用的方式写

// 主对象/中央厨房
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}做好了`)
  }
}

使用

// 顾客张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('糖醋鱼')

image.png

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

小伙伴们应该能发现

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

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

完结

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

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

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

image.png