发布&订阅
一对多
不管是前端还是后端,使用场景最广泛的设计模式,后端的RabbitMQ队列也使用了这种模式
// 主题,接收状态变化,触发每个观察者
class Subject {
constructor() {
this.state = 0
this.observers = []
}
getState() {
return this.state
}
setState(state) {
this.state = state
this.notifyAllObservers()
}
attach(observer) {
this.observers.push(observer)
}
notifyAllObservers() {
this.observers.forEach(observer => {
observer.update()
})
}
}
// 观察者,等待被触发
class Observer {
constructor(name, subject) {
this.name = name
this.subject = subject
this.subject.attach(this)
}
update() {
console.log(`${this.name} update, state: ${this.subject.getState()}`)
}
}
// 测试代码
let s = new Subject()
let o1 = new Observer('o1', s)
let o2 = new Observer('o2', s)
let o3 = new Observer('o3', s)
s.setState(1)
s.setState(2)
s.setState(3)
场景
网页事件绑定
<button id='btn1'>按钮</button>
<script>
$('#btn1').click(function() {
console.log(1);
})
</script>
promise
function loadImg(src) {
let p = new Promise(function(resolve, reject) {
let img = document.createElement('img');
img.onload = function() {
resolve(img)
};
img.onerror = function() {
reject('图片加载失败')
};
img.src = src;
})
return p;
}
let src = 'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2054160543,3972664456&fm=26&gp=0.jpg';
let result = loadImg(src);
result.then(function(img) {
console.log('width', img.width);
document.body.append(img);
return img;
}).then(function(img) {
document.body.append(img);
console.log('height', img.height);
})
jQuery Callbacks
let callbacks = $.Callbacks();
callbacks.add(function(info) {
console.log('fn1', info);
})
callbacks.add(function(info) {
console.log('fn2', info);
})
callbacks.add(function(info) {
console.log('fn3', info)
})
callbacks.fire('gogogo');
callbacks.fire('fire');
nodejs自定义事件
const EventEmitter = require('events').EventEmitter;
const emitter1 = new EventEmitter();
emitter1.on('some', () => {
//监听some事件
console.log('some event is occured 1');
})
emitter1.on('some', () => {
//监听some事件
console.log('some event is occured 2');
})
emitter1.emit('some');
//Stream 用到了自定义事件
let fs = require('fs');
let readStream = fs.createReadStream('./data/file.txt');
let length = 0;
readStream.on('data', function(chunk) {
length += chunk.toString().length;
})
readStream.on('end', function() {
console.log(length);
})
//readline 用到了自定义事件
let readline = require('readline');
let fs = require('fs');
let rl = readline.createInterface({
input: fs.createReadStream('./data/file.txt')
})
let linenum = 0;
rl.on('line', function(line) {
linenum++
})
rl.on('close', function() {
console.log('linenum', linenum)
})
其他场景
- nodejs中:处理http请求、多进程通讯
- vue和react组件生命周期触发
- vue watch
设计原则
- 主题和观察者分离,不是主动触发而是被动监听,2者解耦
- 符合开闭原则
网友评论