观察者模式
1. 介绍
- 发布订阅
- 一对一(多)
2. UML 演示
3. 代码演示
//观察者
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()}`)
}
}
//状态变化之后触发所有观察者对象
class Subject {
constructor() {
this.observers = []
this.state = 0
}
getState() {
return this.state
}
setState(state) {
this.state = state
this.notifyAllObservers()
}
notifyAllObservers() {
this.observers.forEach(observer => {
observer.update()
})
}
attach(observer) {
this.observers.push(observer)
}
}
//测试
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)
4. 场景
4.1 网页事件绑定
<button id="btn1">btn</button>
<script>
$('btn1').click(function(){
console.log(1)
})
$('btn1').click(function(){
console.log(2)
})
$('btn1').click(function(){
console.log(3)
})
</script>
4.2 Promise
function loadImg(src) {
let promise = new Promise(function(resolve, reject) {
let img = document.createElement('img')
img.onload = function() {
resolve(img)
}
img.onerror = function() {
reject('图片加载失败')
}
img.src = src
})
return promise
}
let src = '//img.mukewang.com/5bc45ce20001976409360316.jpg'
let result = loadImg(src)
result
.then(function(img) {
alert(`width:${img.width}`)
})
.then(function(img) {
alert(`height:${img.height}`)
})
.catch(function(ex) {
alert(ex)
})
4.3 jQuery callbacks
var callbacks = $.Callbacks() //注意大小写
callbacks.add(function(info) {
console.log('f1n', info)
})
callbacks.add(function(info) {
console.log('fn2', info)
})
callbacks.add(function(info) {
console.log('fn3', info)
})
callbacks.fire('gogogo')
callbacks.fire('fire')
4.4 nodejs 自定义事件
-
emitter
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') }) //触发some事件 emitter1.emit('some')
-
emit 中传递参数
const EventEmitter = require('events').EventEmitter const emitter = new EventEmitter() emitter.on('some', name => { //监听some事件 console.log('some event', name) }) eemitter.emit('some', 'zhangsan') //emit中可以传递参数
-
任何构造函数都可以继承 EventEmitter 的方法(on、emit)
const EventEmitter = require('events').EventEmitter class Dog extends EventEmitter { constructor(name) { super() this.name = name } } var simon = new Dog('simon') simon.on('bark', function() { console.log(this.name, 'braked') }) setInterval(() => { simon.emit('bark') }, 500)
-
Stream
var fs = retuqire('fs') var readStream = fs.createReadStream('.data/file1.txt/') //读取文件的stream var length = 0 readStream.on('data', function(chunk) { length += chunk.toString().length }) readStream.on('end', function() { console.log(length) })
-
readline 用到了自定义事件
const fs = require('fs') const readline = require('readline') let rl = readline.createInterface({ input: fs.createReadStream('./data/file1.txt') }) let lineNum = 0 rl.on('line', function(line) { lineNum++ }) rl.on('close', function() { console.log('lineNum', lineNum) })
-
nodejs 中:处理 http 请求;多进程通讯
function serverCallback(req, res) { var method = req.method.toLowerCase() //获取请求方法 if (method === 'get') { //上文代码示例中处理GET请求的代码 } if (method === 'post') { //接受post请求的内容 var data = '' req.on('data', function(chunk) { //一点一点的接受内容 data += chunk.toString() }) req.on('end', function() { //接受完毕,将内容输出 res.writeHead(200, { 'Content-type': 'text/html' }) res.write(data) res.end() }) } }
-
vue 和 react 组件生命周期触发
-
vue watch
5. 设计原则
- 主题和观察者分离,不是主动触发而是被动监听,两者解耦
- 符合开放封闭原则