本文共 5144 字,大约阅读时间需要 17 分钟。
发布 & 订阅
一对多
示例
传统 UML 类图
简化后的 UML 类图
Observer
,观察者
,有一个 update() 触发方法
Subject
,主题
,可以绑定多个观察者
observers
是个数组 Array
获取状态 getState()
设置状态 setState()
设置状态后
,会触发所有的观察者里的 update 方法
// 主题,保存状态,状态变化之后触发所有观察者对象class Subject { constructor() { this.state = 0 this.observers = [] } getState() { return this.state } setState(state) { this.state = state this.notifyAllObservers() } notifyAllObservers() { // 此方法将当前所有观察者 observers,进行遍历 this.observers.forEach(observer => { // 每个观察者都执行 update() 方法 observer.update() }) } attach(observer) { // 添加新的观察者 this.observers.push(observer) }}// 观察者class Observer { constructor(name, subject) { this.name = name this.subject = subject this.subject.attach(this) // 把观察者添加到当前主题中来 } update() { // 当触发观察者的 update 方法之后,把 Subject 中的状态 state 打印出来 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)
网页事件绑定
以及所有的UI
、webview
这种层面的事件监听的机制
全部用观察者模式 监听用户点击、拖拽
等// 如何生成一个Promise,并且返回Promisefunction loadImg(src) { var promise = new Promise(function (resolve, reject) { var img = document.createElement('img') img.onload = function () { resolve(img) } img.onerror = function () { reject('图片加载失败') ] img.src = src }) return promise}
// 发布订阅的关系var src = 'https://www.imooc.com/static/img/index/logo_new.png'var result = loadImg(src)result.then(function (img) { // 先绑定函数,不会立刻执行,因为加载图片是需要时间去处理 console.log('width', img.width) return img}).then(function (img) { // 需要等Promise的状态变化才执行 console.log('height', img.height)})
// 自定义事件,自定义回调var 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')
const EventEmitter = require('events').EventEmitter // 引用基础apiconst 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')
const EventEmitter = require('events').EventEmitterconst emitter = new EventEmitter()emitter.on('showName', name => { console.log('event occured', name)})emitter.emit('showName', 'zhangsan') // emit 时候可以传递参数过去
EventEmitter 事件被其他功能继承使用
const EventEmitter = require('events').EventEmitter// 任何构造函数都可以继承 EventEmitter 的方法 on emitclass Dog extends EventEmitter { constructor(name) { super() this.name = name }}var simon = new Dog('simon')simon.on('back', function () { console.log(this.name, 'barked')})setInterval(() => { simon.emit('back')}, 500)
// Stream 用到了自定义事件,监听流数据var fs = require('fs')var readStream = fs.createReadStream('./data/file1.txt') // 读取文件的 Streamvar length = 0readStream.on('data', function (chunk) { length += chunk.toString().length})readStream.on('end', function () { console.log(length)})
// readline 用到了自定义事件,监听行数据var readline = require('readline');var fs = require('fs')var rl = readline.createInterface){ input: fs.createReadStream('./data/file1.txt')});var lineNum = 0rl.on('line', function(line) { lineNum++});rl.on('close', function() { console.log('lineNum', lineNum)});
Node.js 中:处理 http 请求;多进程通讯
// 处理 http 请求function serverCallback(req, res) { var method = req.method.toLowerCase() // 获取请求的方法 if (method === 'get') { // 省略 3 行,上文代码示例中处理 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() }) }}
// 多进程通讯 parent.jsvar cp = require('child_process')var n = cp.fork('./sub.js')n.on('message', function (m) { console.log('PARENT got message: ' + m)})n.send({ hello: 'world'})// sub.jsprocess.on('message', function (m) { console.log('CHILD got message: ' + m)})process.send({ foo: 'bar' })
Vue 和 React 组件生命周期触发
// Reactclass Login extends React.Component { constructor(props, context) { super(props, context); this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this); this.state = { checking: true } } render() { return () } componentDidMount() { // 判断是否已经登录 this.doCheck() }}
Vue watch
// Vuevar vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar' }, watch: { firstName: function (val) { this.fullName = val + ' ' + this.lastName }, lastName: function (val) { this.fullName = this.firstName + ' ' + val } }})
主题和观察者分离,不是主动触发而是被动监听,两者解耦
符合开放封闭原则
转载地址:http://ecqwi.baihongyu.com/