您的位置:首页 > Web前端 > Node.js

node.js笔记之订阅发布设计模式

2018-01-30 11:31 645 查看
当看多了node.js的程序后你会发现特别多的‘订阅发布模式’,大多都是这种监听事件,然后通过回调函数的方式来实现异步操作:

req.on('data',function(){
//do something
});
req.on('end',function(){
//do something
});


所以我又重新学习了一下此设计模式;

参考的文章:友情链接

讲得真的很赞,还有他的博客,值得好好研读学习;我是学习了他的例子,然后进行了解读和修改,不过也发现了此程序中的一个小bug;

代码思路:利用对象的
键-值
作为事件和回调的映射:将我们需要监听的事件名称作为对象的属性,为其创建一个数组,然后将绑定在此事件下的回调函数传入数组进行保存,当触发事件的时候,依次执行数组中的回调函数即可;

bug:当多个回调函数订阅了同一个事件后,然后想去解绑其中一个回调函数的时候,除了最后一个回调函数可以解除外,其余均无效.

这个原因值得注意一下:

for (var i = fns.length - 1,_fn=fns[i]; i >= 0; i--) {
if (_fn === fn) {
// 删除订阅回调函数
fns.splice(i, 1);
}
}


上面是他出问题的代码,将这个循环展开看一下;

var i = fns.length - 1,_fn=fns[i];
while(i>=0)
{
if (_fn === fn) {
// 删除订阅回调函数
fns.splice(i, 1);
}
i--;
}


原因就是在于这个_fn在声明赋值的语句在循环外,值不会进行改变;所以会出现这样的情况,如果要改进的话可以这么改;

for (var i = fns.length - 1,_fn; _fn=fns[i]; i--) {
if (_fn === fn) {
// 删除订阅回调函数
fns.splice(i, 1);
}
}


不过他整体代码还是很精练,值得我们学习,瑕不掩瑜~

改进的地方为:对于多个回调订阅同一事件的时候可以利用数组进行传入,不必每一个都调用listen进行绑定,解除绑定同理;

下面是我改进后的代码:

var Event = (function () {
var clientList = {};
var listen,
trigger,
remove;
listen = function (key, fn) {
if (!clientList[key]) {
clientList[key] = [];
}
if (Object.prototype.toString.call(fn) == "[object Array]") {
clientList[key] = clientList[key].concat(fn);
return
}
clientList[key].push(fn);
};

trigger = function () {
//这里的arguments为调用trigger时传入的参数,以下面的例子来说为['login','处理']
//shift为删除数组的首元素,并返回被删除的这个元素
//这里的key为'login'
var key = [].shift.call(arguments);
var fns = clientList[key];
if (!fns || fns.length === 0) {
return false;
}

for (var i = 0, fn; fn = fns[i++]; ) {
//这里的arguments为['处理']
fn.apply(this, arguments);
}
};

remove = function (key, fn) {
var fns = clientList[key];
var isArray = Object.prototype.toString.call(fn) == "[object Array]" ? true : false;
var len = isArray ? fn.length : 1;
// key对应的消息没有被人订阅
if (!fns) {
return false;
}

// 没有传入fn(具体的回调函数), 表示取消key对应的所有订阅
if (!fn) {
//数组是传址调用,所以这里相当于把clientList[key]清零
fns.length = 0;
} else {
// 反向遍历
for (var j = 0; j < len; j++) {
for (var i = fns.length - 1; i >= 0; i--) {
if (fns[i] === (isArray ? fn[j] : fn)) {
// 删除订阅回调函数
fns.splice(i, 1);
}
}
}
}
};

return {
listen : listen,
trigger : trigger,
remove : remove
}
}());

function handler1(data) {
console.log('1:' + data);
}
function handler2(data) {
console.log('2:' + data);
}
function handler3(data) {
console.log('3:' + data);
}

Event.listen('login', [handler1, handler2, handler3]);
Event.remove('login', [handler1, handler2]);
Event.trigger('login', '处理')
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: