这是我参与「第五届青训营」伴学笔记创作活动的第 4 天
前言
观察者模式 - 前端最常用的设计模式
1. 主要内容
概念介绍,解决的问题
代码演示和 UML 类图
应用场景
观察者模式 vs 发布订阅模式(观察者模式延伸出来的)
发布订阅模式的场景
1)学习方法
UML 类图要结合代码理解
设计模式要结合使用场景,否则会记不住
2)注意事项
观察者模式很重要,本章内容较多,请耐心学习
观察者模式场景很多,要抓住重点,不要拘泥于细节
2. 观察者模式
1)介绍
我不需要一直关注某个交互动作,你在点击交互的时候,告诉我你点击了,然后我再去做更新
DOM 事件就是观察者模式,Vue 生命周期也是观察者模式
2)演示
UML 类图
代码演示
是否符合设计原则?
3)UML 类图
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 事件
2)Vue watch
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)例子介绍
2)观察者模式 vs 发布订阅模式
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 通讯等
全局安装 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)注意事项
观察者模式很重要,本章内容较多,请耐心学习
观察者模式场景很多,要抓住终点,不要拘于细节
实际工作中,不会严格区分观察者模式和发布订阅模式