Appearance
模块间通信
上一节中实现的发布—订阅模式的实现,是基于一个全局的 Event 对象,我们利用它可以在 两个封装良好的模块中进行通信,这两个模块可以完全不知道对方的存在。就如同有了中介公司 之后,我们不再需要知道房子开售的消息来自哪个售楼处。
比如现在有两个模块,a 模块里面有一个按钮,每次点击按钮之后,b 模块里的 div 中会显示 按钮的总点击次数,我们用全局发布—订阅模式完成下面的代码,使得 a 模块和 b 模块可以在保 持封装性的前提下进行通信。
html
<body>
<button id="btn">btn</button>
<div id="div"></div>
<script>
var Event = (function () {
var clientList = {},
listen,
trigger,
remove;
listen = function (key, fn) {
if (!clientList[key]) {
clientList[key] = [];
}
clientList[key].push(fn);
};
trigger = function () {
var key = Array.prototype.shift.call(arguments),
fns = clientList[key];
if (!fns || fns.length === 0) {
return false;
}
for (var i = 0, fn; fn = fns[i++];) {
fn.apply(this, arguments);
}
};
remove = function (key, fn) {
var fns = clientList[key];
if (!fns) {
return false;
}
if (!fn) {
fns && (fns.length = 0);
} else {
for (var l = fns.length - 1; l >= 0; l--) {
var _fn = fns[l];
if (_fn === fn) {
fns.splice(l, 1);
}
}
}
};
return {
listen: listen,
trigger: trigger,
remove: remove
}
})();
const a = (function () {
let count = 0
btn.addEventListener('click', () => {
count++
Event.trigger('add', count)
})
})()
const b = (function () {
Event.listen('add', function (count) {
div.innerText = count
})
})()
</script>
</body>但在这里我们要留意另一个问题,模块之间如果用了太多的全局发布—订阅模式来通信,那 么模块与模块之间的联系就被隐藏到了背后。我们最终会搞不清楚消息来自哪个模块,或者消息 会流向哪些模块,这又会给我们的维护带来一些麻烦,也许某个模块的作用就是暴露一些接口给 其他模块调用。