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);
相关推荐
IT_陈寒2 分钟前
Spring Boot 3.2 新特性全解析:这5个性能优化点让你的应用提速50%!
前端·人工智能·后端
携欢9 分钟前
PortSwigger靶场之Stored DOM XSS通关秘籍
前端·xss
GDAL10 分钟前
Knockout-ES5 入门教程
javascript·knockout
正义的大古11 分钟前
OpenLayers数据源集成 -- 章节八:天地图集成详解
开发语言·javascript·ecmascript·openlayers
LDM>W<20 分钟前
Electron下载失败
前端·javascript·electron
EndingCoder22 分钟前
Electron 新特性:2025 版本更新解读
前端·javascript·缓存·electron·前端框架·node.js·桌面端
BillKu39 分钟前
Vue3 中使用 DOMPurify 对渲染动态 HTML 进行安全净化处理
前端·安全·html
子兮曰1 小时前
🔥深度解析:Nginx目录浏览美化与功能增强实战指南
前端·javascript·nginx
machinecat1 小时前
node,小程序合成音频的方式
前端·node.js
我是日安1 小时前
从零到一打造 Vue3 响应式系统 Day 4 - 核心概念:收集依赖、触发更新
前端·vue.js