也叫观察者模式,定义对象间一对多的依赖关系。
实现发布-订阅模式分3步:
1.确定发布者
2.给发布者添加缓存列表,用来保存回调函数(订阅者)
3.发布消息,遍历缓存列表,依次触发执行回调函数。
var salesOffices = {}; // 定义售楼处
salesOffices.clientList = []; // 缓存列表,存放订阅者的回调函数
salesOffices.listen = function( fn ){ // 增加订阅者
this.clientList.push( fn ); // 订阅的消息添加进缓存列表
};
salesOffices.trigger = function(){ // 发布消息
for( var i = 0, fn; fn = this.clientList[ i++ ]; ){
fn.apply( this, arguments ); // (2) // arguments 是发布消息时带上的参数
}
};
上面的确定是,订阅者会接受所有的信息,包括自己不感兴趣的。
需要增加一个标识符:
var salesOffices = {}; // 定义售楼处
salesOffices.clientList = []; // 缓存列表,存放订阅者的回调函数
salesOffices.listen = function( key, fn ){
if ( !this.clientList[ key ] ){ // 如果还没有订阅过此类消息,给该类消息创建一个缓存列表
this.clientList[ key ] = [];
}
this.clientList[ key ].push( fn ); // 订阅的消息添加进消息缓存列表
};
salesOffices.trigger = function(){ // 发布消息
var key = Array.prototype.shift.call( arguments ), // 取出消息类型
fns = this.clientList[ key ]; // 取出该消息对应的回调函数集合
if ( !fns || fns.length === 0 ){ // 如果没有订阅该消息,则返回
return false;
}
for( var i = 0, fn; fn = fns[ i++ ]; ){
fn.apply( this, arguments ); // (2) // arguments 是发布消息时附送的参数
}
};
还可以继续优化,将功能提取出来。这样可以给每个对象都动态安装发布-订阅功能:
//所以我们把发布—订阅的功能提取出来,放在一个单独的对象内:
var event = {
clientList: [],
listen: function( key, fn ){
if ( !this.clientList[ key ] ){
this.clientList[ key ] = [];
}
this.clientList[ key ].push( fn ); // 订阅的消息添加进缓存列表
},
trigger: function(){
var key = Array.prototype.shift.call( arguments ), // (1);
fns = this.clientList[ key ];
if ( !fns || fns.length === 0 ){ // 如果没有绑定对应的消息
return false;
}
for( var i = 0, fn; fn = fns[ i++ ]; ){
fn.apply( this, arguments ); // (2) // arguments 是trigger 时带上的参数
}
}
};
var installEvent = function( obj ){
for ( var i in event ){
obj[ i ] = event[ i ];
}
};
//再来测试一番,我们给售楼处对象salesOffices 动态增加发布—订阅功能:
var salesOffices = {};
installEvent( salesOffices );
- 网站登录例子
实际场景的应用,思考用回调和发布订阅模式的不同;发布订阅的优势?
// 回调
login.succ(function(data){
// 处理 header nav 逻辑
})
// 发布订阅
var header = {
setAvatar: function(data){
// 处理逻辑
}
}
login.listen('loginSucc',function(data){
header.setAvatar(data);
})
$.ajax(url,function(data){
login.trigger('loginSucc',data);
})
- 全局的发布-订阅模式
发布-订阅用一个全局的Event对象来实现;这样发布者和订阅者就断了联系,Event类似一个‘中介者’的角色,可以把两者联系起来。
// 订阅消息
Event.listen( 'squareMeter88', function( price ){
console.log( '价格= ' + price ); // 输出:'价格=2000000'
});
// 售楼处发布消息
Event.trigger( 'squareMeter88', 2000000 );
- 模块间通信