前言:上一章,我们介绍了发布订阅模式的实现和其与观察者模式之间的联系。这一章我们来看一下 npm 上比较优秀的 pubsub-js 库的内部实现。
pubsub-js 的 API 总和
API |
功能 |
subscribe |
订阅一个主题,并绑定事件处理函数 |
subscribeOnce |
订阅一个主题,执行一次后,立即注销订阅 |
publish |
异步发布消息 |
publishSync |
同步发布消息 |
clearSubscriptions |
中等文本 |
clearAllSubscriptions |
中等文本 |
unsubscribe |
注销订阅特定主题 |
下面我们将逐一分析上述 api 的实现,此处为pubsub-js 的 npm 地址
总体数据结构
1 2 3
|
var messages = {}, lastUid = -1;
|
subscribe 实现
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
|
PubSub.subscribe = function (message, func) {
if (typeof func !== 'function') return false;
message = (typeof message === 'symbol') ? message.toString() : message;
if (!messages.hasOwnProperty(message)) { messages[message] = {}; }
var token = 'uid_' + String(++lastUid); messages[message][token] = func;
return token; };
|
subscribeOnce 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
PubSub.subscribeOnce = function (message, func) { var token = PubSub.subscribe(message, function () { PubSub.unsubscribe(token); func.apply(this, arguments); }); return PubSub; };
|
publish & publishSync 实现
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
|
PubSub.publishSync = function( message, data ){ return publish( message, data, true, PubSub.immediateExceptions ); };
PubSub.publish = function (message, data) { return publish(message, data, false, PubSub.immediateExceptions); };
function publish(message, data, sync, immediateExceptions) {
message = (typeof message === 'symbol') ? message.toString() : message;
var deliver = createDeliveryFunction(message, data, immediateExceptions), hasSubscribers = messageHasSubscribers(message);
if (!hasSubscribers) { return false; }
if (sync === true) deliver(); else setTimeout(deliver, 0); return true; }
|
clearSubscriptions 实现
1 2 3 4 5 6 7 8 9 10 11 12
|
PubSub.clearSubscriptions = function clearSubscriptions(topic) { var m; for (m in messages) { if (messages.hasOwnProperty(m) && m.indexOf(topic) === 0) { delete messages[m]; } } };
|
clearAllSubscriptions 实现
1 2 3 4 5 6
|
PubSub.clearAllSubscriptions = function clearAllSubscriptions() { messages = {}; };
|
unsubscribe 实现
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 70
|
PubSub.unsubscribe = function (value) {
var descendantTopicExists = function (topic) { for (var m in messages) { if (messages.hasOwnProperty(m) && m.indexOf(topic) === 0) return true; } return false; }, isTopic = typeof value === 'string' && (messages.hasOwnProperty(value) || descendantTopicExists(value)), isToken = !isTopic && typeof value === 'string', isFunction = typeof value === 'function', result = false, m, message, t;
if (isTopic) { PubSub.clearSubscriptions(value); return; }
for (m in messages) { if (messages.hasOwnProperty(m)) { message = messages[m];
if (isToken && message[value]) { delete message[value]; result = value; break; }
if (isFunction) { for (t in message) { if (message.hasOwnProperty(t) && message[t] === value) { delete message[t]; result = true; } } } } }
return result; };
|