组件库项目中运用的观察者模式 | 青训营笔记

110 阅读4分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 4 天

前言

观察者模式 - 前端最常用的设计模式

1. 主要内容

概念介绍,解决的问题

代码演示和 UML 类图

应用场景


观察者模式 vs 发布订阅模式(观察者模式延伸出来的)

发布订阅模式的场景

1)学习方法

UML 类图要结合代码理解

设计模式要结合使用场景,否则会记不住

2)注意事项

观察者模式很重要,本章内容较多,请耐心学习

观察者模式场景很多,要抓住重点,不要拘泥于细节

2. 观察者模式

1)介绍

我不需要一直关注某个交互动作,你在点击交互的时候,告诉我你点击了,然后我再去做更新

DOM 事件就是观察者模式,Vue 生命周期也是观察者模式

2)演示

UML 类图

代码演示

是否符合设计原则?

3)UML 类图

image-20230109100839097

4)代码演示

 class Subject {
   private state: number = 0;
   private observers: Observer[] = [];
 ​
   getState() {
     return this.state;
   }
   setState(newState: number) {
     this.state = newState;
     this.notify();
   }
   notify() {
     this.observers.forEach(item => {
       item.update(this.state);
     });
   }
   attach(observer: Observer) {
     this.observers.push(observer);
   }
 }
 ​
 class Observer {
   name: string;
   constructor(name: string) {
     this.name = name;
   }
   update(state: number) {
     console.log(`${this.name} updated, state is ${state}`);
   }
 }
 ​
 const sub = new Subject();
 sub.attach(new Observer("A"));
 sub.attach(new Observer("B"));
 sub.setState(1);
 console.log(sub.getState());

5)是否符合设计原则

Observer 和 Subject 分离,解耦

Observer 可自由扩展

Subject 可自有扩展

3. 观察者模式 - 场景

DOM 事件

Vue React 组件生命周期

Vue watch

Vue 组件更新过程

各种异步回调

MutationObserver

1)DOM 事件

image-20230109103239730

2)Vue watch

image-20230109103459331

3)各种异步回调函数

定时器 setTimeout setInterval

Promise.then

Nodejs - stream readline httpServer

  • stream(流,将文件切割成一段一段,不会按行来):一块一块将文件读取,最大读取量为 65536

     const fs = require('fs')
     const readStream = fs.createReadStream('./data/yarn.lock.txt')
     ​
     // 文件字符的 length
     let length = 0
     ​
     readStream.on('data', function(chunk){
       const curLength = chunk.toString().length
       console.log('current length', curLength)
       length += curLength
     })
     readStream.on('end', function(){
       console.log(length)
     })
    
  • readline(将文件切割成一行一行):

     const readline = require('raedline')
     const fs = require('fs')
     ​
     const rl = readline.createInterface({
       input: fs.createReadStream('./data/yarn.lock.txt')
     })
     ​
     // 文件有多少行
     let lineNum = 0
     rl.on('line', function (line) {
       lineNum++
     })
     rl.on('close', function () {
       console.log('lineNum', lineNum)
     })
    

4)MutationObserver

 // MutationObserver 的回调函数
 function callback(records: MutationRecord[], observer: MutationObserver) {
   for (const record of records) {
     console.log(record);
   }
 }
 ​
 // 创建一个监听实例,触发监听调用 callback 实例
 const observer = new MutationObserver(callback);
 ​
 const elem = document.getElementById("container");
 if (elem) {
   // 开始启动监听
   observer.observe(elem, {
     // 监听配置,什么变化才触发监听
     attributes: true, // 监听属性变化
     attributeOldValue: true, // 变化之后,之前的旧值
     childList: true, // 监听子节点的变化(增加,删除)
     characterData: true, // 监听节点的内容或文本变化
     subtree: true, // 递归监听下级所有节点
   });
 }
 ​
 // 关闭监听
 // 在开启监听的话,把 observer.observe 执行一遍即可
 observer.disconnect();

4. 发布订阅模式

不属于传统的 23 种设计模式

是观察者模式的另一种实现方式

实际工作中,不会区分的那么细致(但学习要区分细致)

1)例子介绍

image-20230109112738893

2)观察者模式 vs 发布订阅模式

image-20230109112832579

3)区别

观察者:Subject和Observer直接绑定,中间无媒介

发布订阅:Publisher和Observer互不相识,中间有媒介

【小技巧】看是否需要手动触发 emit,手动触发则是发布订阅模式

4)场景

自定义事件

postMessage 通讯

A. 自定义事件

Vue2 本身就是一个 EventBus

Vue3 不再自带 EventBus 功能,推荐使用 mitt

老牌 EventBus - eventEmitter

B. postMessage 通讯

[6.10]--6-14发布订阅模式的场景-postMessage通讯

网页和 iframe 的通讯

其他:多进程(nodejs WebWorker)通讯,WebSocket 通讯等


image-20230109154908381

全局安装 http-server:npm i http-server-g 打开控制台,进入html-code目录,执行 http-server -p 8881 浏览器访问`http://localhost:8881/

5)注意事项:自定义事件要及时 off

组件销毁之前 off,避免内存泄露

off 时要传入之前的函数(而非匿名函数)

6)总结

什么是发布订阅模式

  • 既有发布也有订阅,可以自己订阅,也可以 emit 去触发

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

发布订阅模式的场景

  • 自定义事件
  • postMessage 通讯

5. 总结

1)内容回顾

概念介绍,解决的问题(适用于UI编程)

代码演示和 UML 类图

应用场景

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

发布订阅模式的场景

2)重要细节

Vue3 不在自带 EventBus 功能

组件销毁时要及时 off 自定义事件

3)注意事项

观察者模式很重要,本章内容较多,请耐心学习

观察者模式场景很多,要抓住终点,不要拘于细节

实际工作中,不会严格区分观察者模式和发布订阅模式