Dust8 的博客

读书百遍其义自见

0%

发布订阅模式

发布订阅模式有很多名字,例如观察者模式.
观察者模式是一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个”观察”该对象的其他对象.

例子

发布订阅模式在编程里面很常见.下面举些例子.

javascrip

在js 里面经常用到的

  • addEventListener
  • dispatchEvent
  • removeEventListener

websocket

  • open
  • message
  • error
  • close
1
2
3
4
5
6
7
8
9
10
11
12
// Create WebSocket connection.
const socket = new WebSocket('ws://localhost:8080');

// Connection opened
socket.addEventListener('open', function (event) {
socket.send('Hello Server!');
});

// Listen for messages
socket.addEventListener('message', function (event) {
console.log('Message from server ', event.data);
});

Vue

  • vm.$on
  • vm.$once
  • vm.$off
  • vm.$emit
    1
    2
    3
    4
    5
    vm.$on('test', function (msg) {
    console.log(msg)
    })
    vm.$emit('test', 'hi')
    // => "hi"

即时通信 IM SDK

  • on
  • off
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
tim.on(TIM.EVENT.MESSAGE_RECEIVED, function(event) {
// 收到推送的单聊、群聊、群提示、群系统通知的新消息,可通过遍历 event.data 获取消息列表数据并渲染到页面
// event.name - TIM.EVENT.MESSAGE_RECEIVED
// event.data - 存储 Message 对象的数组 - [Message]
});

tim.on(TIM.EVENT.MESSAGE_MODIFIED, function(event)) {
// 收到消息被第三方回调修改的通知,消息发送方可通过遍历 event.data 获取消息列表数据并更新页面上同 ID 消息的内容(v2.12.1起支持)
// event.name - TIM.EVENT.MESSAGE_MODIFIED
// event.data - 存储被第三方回调修改过的 Message 对象的数组 - [Message]
});

tim.on(TIM.EVENT.MESSAGE_REVOKED, function(event) {
// 收到消息被撤回的通知。使用前需要将SDK版本升级至v2.4.0或更高版本
// event.name - TIM.EVENT.MESSAGE_REVOKED
// event.data - 存储 Message 对象的数组 - [Message] - 每个 Message 对象的 isRevoked 属性值为 true
});

tim.on(TIM.EVENT.MESSAGE_READ_BY_PEER, function(event) {
// SDK 收到对端已读消息的通知,即已读回执。使用前需要将SDK版本升级至v2.7.0或更高版本。仅支持单聊会话
// event.name - TIM.EVENT.MESSAGE_READ_BY_PEER
// event.data - event.data - 存储 Message 对象的数组 - [Message] - 每个 Message 对象的 isPeerRead 属性值为 true
});

tim.on(TIM.EVENT.CONVERSATION_LIST_UPDATED, function(event) {
// 收到会话列表更新通知,可通过遍历 event.data 获取会话列表数据并渲染到页面
// event.name - TIM.EVENT.CONVERSATION_LIST_UPDATED
// event.data - 存储 Conversation 对象的数组 - [Conversation]
});

核心内容

一个发布者,一个或多个订阅者

  • 一个订阅的方法
  • 一个发布的方法
  • 一个取消订阅的方法

如何通用实现

也可以看 [JavaScript设计模式与开发实践] 这本书里面的 “第8章 发布—订阅模式”, 里面说的比较细

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// event.js

class Event {

/**
* on 方法把订阅者所想要订阅的事件及相应的回调函数记录在 Event 对象的 _cbs 属性中
*/
on (event, fn) {
if (typeof fn != "function") {
console.error('fn must be a function')
return
}

this._cbs = this._cbs || {}
;(this._cbs[event] = this._cbs[event] || []).push(fn)
}


/**
* emit 方法接受一个事件名称参数,在 Event 对象的 _cbs 属性中取出对应的数组,并逐个执行里面的回调函数
*/
emit (event) {
this._cbs = this._cbs || {}
var callbacks = this._cbs[event], args

if (callbacks) {
callbacks = callbacks.slice(0)
args = [].slice.call(arguments, 1)
for (var i = 0, len = callbacks.length; i < len; i++) {
callbacks[i].apply(null, args)
}
}
}



/**
* off 方法接受事件名称和当初注册的回调函数作参数,在 Event 对象的 _cbs 属性中删除对应的回调函数。
*/
off (event, fn) {
this._cbs = this._cbs || {}

// all
if (!arguments.length) {
this._cbs = {}
return
}

var callbacks = this._cbs[event]
if (!callbacks) return

// remove all handlers
if (arguments.length === 1) {
delete this._cbs[event]
return
}

// remove specific handler
var cb
for (var i = 0, len = callbacks.length; i < len; i++) {
cb = callbacks[i]
if (cb === fn || cb.fn === fn) {
callbacks.splice(i, 1)
break
}
}
return
}
}

参考链接