1.从监听与发布说起
我们写js代码的时候都知道有这样的事件:我们注册一个click方法 ,此时我们就为这个按钮添加了“监听”,基于“点击”事件的监听。以此来实现点击按钮提交表单数据的目的,在这里,我们通过点(发)击(布)这个动作,让系统知道:哦,我要提交这些表单。 这里的click方法,就是我们所要说的 “发布”。
2.发布消息之后发生了什么
当我发布登录消息的时候,就有很多模块来响应,比如我登录博客,页面的头部展示我的私人信息,首页展示我的博客内容等。就会有很多模块用各自方法对这个信息进行处理,那么这些方法存放在哪里呢?我可以创建一个对象
<script type="text/javascript">
var callback = {};
</script>
这些方法有很多,而每个方法又对应很多回调函数,我需要对这些方法数据进行梳理:
<script type="text/javascript">
var callback = {
login: [
function(){},//head回调
function(){}//内容回调
],
req: [
function(){},
function(){}
]
...
}
</script>
比如:我发出 login 消息,就要找到login对应的回调方法,去处理login产生的结果,将结果存储在callback里。
3.一般的消息处理方法
比如有一个登录框,我登录成功后页面顶部改变,内容区域显示我的个人信息,一般我们可以这样写:
<script type="text/javascript">
(function() {
$.ajax({
url:'http://blog.csdn.net/lihchweb',
data:{},
success: function() {
//成功了
$("#head name").html("lihouchun");
$("#content").html(infos);
//....
//....
}
})
})();
</script>
这显然不是我们想要的,一方面他并没有模块化,代码逻辑容易混乱,也造成了内部的变量命名比较混乱。另一方面:因为登录的代码逻辑影响着其他部分,它自身又不能很好的维护自身的所有逻辑。
而我们又想要去解决这个问题,那么发布,订阅,消息系统来了。
4. 改进的方法:降低耦合度,维护自身逻辑
先看写法:
<script type="text/javascript">
//我是head的代码逻辑
(function(){
core.listen('login', function(info) {
$("#head name").html(info.name);
});
})()
//我是content的代码逻辑
(function() {
core.listen('login', function(info) {
$("#content").html(info.content);
})
})()
//我是登录的逻辑
(function() {
$.ajax({
url:'http://blog.csdn.net/lihchweb',
data:{},
success: function(info) {
core.send('login', info)
}
})
})();
</script>
这样处理问题的方法就回到的各自的逻辑当中。当我登录完成的时候,各个部分单独处理自己的问题,模块更独立,代码易维护且不易出错。
这就是消息机制。
这个core是自定义的,你可以定义lihch当然其他什么都行。
接下来就回到了我们最初的问题,要将这些数据存储起来。如下:
<script type="text/javascript">
var callback = {
login: [],
req:[],
lihch:[]
}
var core = {
listen: function(id, handler) {
callback[id].push(handler)
},
send: function(id, data) {
var cbs = callback[id];
for (var i = 0; i < cbs.length; i++) {
cbs[i](data);
}
}
</script>
在listen里: 我们将得到的方法(lihch方法,req方法,login方法等)添加(push)到数组里。
在send里: 我们遍历listen中存储的方法(比如(lihch方法))。并逐个触发:lihch(data);
5.更好的方法
上面4方法中有两个全局变量:callback core 我们尝试将其合并起来:
var core = {
callback: {
login: [],
req:[],
lihch:[]
},
listen: function(id, handler) {
this.callback[id].push(handler)
},
send: function(id, data) {
var cbs = callback[id];
for (var i = 0; i < cbs.length; i++) {
cbs [i](data);
}
}
}
这样对面只暴露一个core,通过core.listen, core.send去执行。
这样看似很美好,但是这个core.callback 谁都可以访问到,在多人配合的情况下,难免出现类似于这样的问题: core.callback = null;
好吧 ,那所有注册的方法都失效了。为了保护它,我们继续修改:
var core = (function() {
var callback = {
login: [],
req:[],
lihch:[]
};
return {
listen: function(id, handler) {
callback[id].push(handler)
},
send: function(id, data) {
var cbs = callback[id];
for (var i = 0; i < cbs.length; i++) {
cbs [i](data);
}
}
}
})();
我们把他放进一个闭包里面,只暴露listen和send这个两个接口。callback是被包在core内部的变量,外部是访问不到的。
但是这个时候还有一个问题: callback里我们预设了lihch,login,req方法,但是我们又不知道页面中到底会传过来什么用的消息,那如果要监听的是 lihouchun 呢, 有要修改上面的代码,在callback里加上 lihouchun: [];
显然这样也不是我们想要的,能不能让他智能点呢?
var core = (function() {
var callback = {};
return {
listen: function(id, handler) {
callback[id] = callback[id] || [];
callback[id].push(handler)
},
send: function(id, data) {
var cbs = callback[id];
if (!cbs) return;
for (var i = 0; i < cbs.length; i++) {
cbs [i](data);
}
}
}
})();
这样,烦恼没有了,listen的时候他会自动判断添加,并且send的时候也做了处理。
这就是消息机制,有了它,对代码的耦合性就大大降低,模块更加独立,容错性更强。
此文后续: 观察者模式和发布订阅模式。 链接:
https://blog.csdn.net/lihchweb/article/details/104001403