javaScript 观察者模式和发布订阅模式

观察者模式和发布订阅模式

基本概念

发布订阅模式

在这个模式中,发布者(或者说是主题)并不直接发送消息给订阅者,而是通过调度中心(或者叫消息代理)来传递消息。 发布者(或者说是主题)并不知道订阅者的存在,而订阅者也不知道发布者的存在。他们彼此唯一的关系就是在调度中心注册成为订阅者或者发布者。

观察者模式

观察者(Observer)模式中包含两种对象,分别是目标对象和观察者对象。在目标对象和观察者对象间存在着一种一对多的对应关系,当这个目标对象的状态发生变化时,所有依赖于它的观察者对象都会得到通知并执行它们各自特有的行为。

区别

简单来讲,观察者模式是基于发布订阅模式的,发布订阅模式需要手动进行订阅和发布,是基于中间的调度栈进行的,可以不发布,也可以不订阅,发布订阅是解偶没有关联的,而观察者模式是有相互依赖关系的,并且观察者必须实现一个update方法提供调用。

发布订阅者模式示例

  • 如下,有两个异步获取文件的函数,在不使用promise的情况下,需要在读取到两个文件后执行finish。
js 复制代码
const fs = require('fs'); // 引入node中的fs模块
fs.readFile('./1.text', 'utf8', function (error, data) {
 	console.log('读取到了文件1.text'); 
});
fs.readFile('./2.text', 'utf8', function (error, data) {
 	console.log('读取到了文件2.text'); 
});
function finish() {
  console.log('文件读取完成');
}
  • 利用发布订阅模式,实现一个中间调度栈event
  • event需要缓存发布的数据的数据和订阅回调函数
  • event需要实现on和emit方法提供发布和订阅功能
    • on接收一个函数作为参数,并且将该函数进行缓存,等待发布消息后按顺序执行。
    • emit接收key和value两个参数,作为发布的键值对数据进行缓存,订阅函数被执行是传入。
js 复制代码
const event = {
  _arr: [], // 用于缓存所有订阅的回调函数
  data: {}, // 用于缓存发布的数据
  on(fn) {
    // 直接缓存订阅函数
    this._arr.push(fn);
  },
  emit(key, value) {
    // 发布数据,直接缓存数据并且执行所有的订阅函数。
    this.data[key] = value;
    this._arr.forEach(fn => fn(this.data));
  }
}
  • 最后使用该调度栈进行简单的发布订阅
js 复制代码
const fs = require('fs'); // 引入node中的fs模块
const event = {
  _arr: [], // 用于缓存所有订阅的回调函数
  data: {}, // 用于缓存发布的数据
  on(fn) {
    // 直接缓存订阅函数
    this._arr.push(fn);
  },
  emit(key, value) {
    // 发布数据,直接缓存数据并且执行所有的订阅函数。
    this.data[key] = value;
    this._arr.forEach(fn => fn(this.data));
  }
}

event.on((data) => { // 订阅
  console.log('当前读取到的文件', data);
});
event.on((data) => { // 订阅
  if (Reflect.ownKeys(data).length === 2) { // 等价于Object.Keys()
    finish();
  }
});

fs.readFile('./1.text', 'utf8', function (error, data) {
 	console.log('读取到了文件1.text'); 
  event.emit('text1', '1111'); // 发布
});
fs.readFile('./2.text', 'utf8', function (error, data) {
 	console.log('读取到了文件2.text'); 
  event.emit('text2', '2222'); // 发布
});
function finish() {
  console.log('文件读取完成');
  event.emit(); // 发布
}

观察者模式

  • 观察者模式分为观察者被观察者两个类。
  • 被观察者需要接收观察者。
  • 观察者需要提供update方法。
js 复制代码
// 被观察者
class Subject {
  constructor() {
    this.observers = []; // 用于接收观察者
    this.state = false; // 当前的被观察者状态
  }
  attach(fn) {
    this.observers.push(fn); // 订阅模式,被观察者接收观察者
  }
  setState(newValue) {
    this.state = newValue; // 修改状态
   	// 当状态变化时,需要通知所有观察者,调用观察者的update方法.
    this.observers.forEach(fn => fn.update(newValue));
  }
}

// 观察者
class Observer {
  update() {
    console.log('收到了通知!');
  }
}

const a = new Subject();
const b = new Observer();
const c = new Observer();
a.attach(o1); // 订阅
a.attach(o2); // 订阅

// 修改被观察者状态
a.setState(false);
相关推荐
大怪v6 小时前
AI抢饭?前端佬:我要验牌!
前端·人工智能·程序员
新酱爱学习6 小时前
字节外包一年,我的技术成长之路
前端·程序员·年终总结
小兵张健6 小时前
开源 playwright-pool 会话池来了
前端·javascript·github
IT_陈寒9 小时前
Python开发者必知的5大性能陷阱:90%的人都踩过的坑!
前端·人工智能·后端
codingWhat9 小时前
介绍一个手势识别库——AlloyFinger
前端·javascript·vue.js
Lee川9 小时前
深度拆解:基于面向对象思维的“就地编辑”组件全模块解析
javascript·架构
代码老中医10 小时前
2026年CSS彻底疯了:这6个新特性让我删掉了三分之一JS代码
前端
进击的尘埃10 小时前
Web Worker 与 OffscreenCanvas:把主线程从重活里解放出来
javascript
不会敲代码110 小时前
Zustand:轻量级状态管理,从入门到实践
前端·typescript
踩着两条虫10 小时前
VTJ.PRO 双向代码转换原理揭秘
前端·vue.js·人工智能