flashfxp怎么上传网站,网站建设用款,网页设计的背景与意义,手机网页怎么做出来的文章目录 1、现实中的发布#xff0d;订阅模式2、DOM 事件3、简单的发布-订阅模式4、通用的发布-订阅模式5、先发布再订阅6、小结 发布—订阅模式又叫观察者模式#xff0c;它定义对象间的一种一对多的依赖关系#xff0c;当一个对象的状态发生改变时#xff0c;所有依赖于… 文章目录 1、现实中的发布订阅模式2、DOM 事件3、简单的发布-订阅模式4、通用的发布-订阅模式5、先发布再订阅6、小结 发布—订阅模式又叫观察者模式它定义对象间的一种一对多的依赖关系当一个对象的状态发生改变时所有依赖于它的对象都将得到通知。在 JavaScript 开发中我们一般用事件模型来替代传统的发布—订阅模式
1、现实中的发布订阅模式
小明最近看上了一套房子到了售楼处之后才被告知该楼盘的房子早已售罄。好在售楼 处告诉小明不久后还有一些尾盘推出。于是小明离开之前把电话号码留在了售楼处相同的还有小红小强。于是新楼盘推出的时候售楼处会翻开花名册遍历上面的电话号码依次发送一条短信来通知他们
2、DOM 事件
只要我们曾经在 DOM 节点上面绑定过事件函数那我们就曾经使用过发布—订阅模式
document.body.addEventListener( click, function(){ alert(2);
}, false ); document.body.click(); // 模拟用户点击3、简单的发布-订阅模式
发布-订阅模式的实现步骤 1、定义发布者 2、给发布者添加一个缓存列表用于存放回调函数以便通知订阅者 3、最后发布消息的时候发布者会遍历这个缓存列表依次触发里面存放的订阅者回调函数
代码示例
var salesOffices {}; // 定义发布者
salesOffices.clientList []; // 缓存列表存放订阅者的回调函数
salesOffices.listen function (fn) {// 增加订阅者this.clientList.push(fn); // 订阅的消息添加进缓存列表
};
salesOffices.trigger function () {// 发布消息for (var i 0; i this.clientList.length; i) {var fn this.clientList.length;fn.apply(this, arguments); // arguments 是发布消息时带上的参数}
};测试
salesOffices.listen(function (price, squareMeter) {// 小明订阅消息console.log(小明价格 price);console.log(小明squareMeter squareMeter);
});
salesOffices.listen(function (price, squareMeter) {// 小红订阅消息console.log(小红价格 price);console.log(小红squareMeter squareMeter);
});salesOffices.trigger(2000, 300);
salesOffices.trigger(2000, 700);问题 订阅者接收到了发布者发布的每个消息有些并不是订阅者需要的
解决 要增加一个标示 key让订阅者只订阅自己感兴趣的消息 改写代码
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); // 取出消息类型var fns this.clientList[key]; // 取出该消息对应的回调函数集合if (!fns || fns.length 0) {// 如果没有订阅该消息则返回return false;}for (var i 0; i fns.length; i) {var fn fns[i];fn.apply(this, arguments); // (2) // arguments 是发布消息时附送的参数}
};测试
salesOffices.listen(squareMeter88, function (price) {// 小明订阅 88 平方米房子的消息console.log(价格 price); // 输出 2000000
});
salesOffices.listen(squareMeter110, function (price) {// 小红订阅 110 平方米房子的消息console.log(价格 price); // 输出 3000000
});salesOffices.trigger(squareMeter88, 30000);
salesOffices.trigger(squareMeter110, 70000);4、通用的发布-订阅模式
包含发布-订阅取消订阅
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);var fns this.clientList[key];if (!fns || fns.length 0) {return false;}for (var i 0, fn; (fn fns[i]); ) {fn.apply(this, arguments);}},// 增加 remove 方法remove(key, fn) {var fns this.clientList[key];if (!fns) {return false;}if (!fn) {fns (fns.length 0);} else {for (var i fns.length - 1; i 0; i--) {var _fn fns[i];if (fn _fn) {fns.splice(i, 1);}}}},
};测试
var f1 function (price) {console.log(价格 price);
};
Event.listen(s88, f1);var f2 function (price) {console.log(价格 price);
};
Event.listen(s110, f2);Event.remove(s110, f2); // 删除订阅Event.trigger(s88, 30000);
Event.trigger(s110, 70000);5、先发布再订阅
应用场景发布者发布的内容不管订阅者在发布之前订阅或者发布之后订阅都可触发订阅者订阅的内容
代码
var Event (function () {var clientList {};var offlineStack {}; // 离线缓存参数var triggerStack {}; // 已触发trigger的参数缓存var listen;var trigger;var remove;listen function (key, fn) {if (!clientList[key]) {clientList[key] [];}clientList[key].push(fn);// 如果此时订阅的事件已经发布了则自定触发一次订阅内容fnif (triggerStack[key]) {fn.apply(this, triggerStack[key]);} else if (offlineStack[key]) {// 如果是离线状态则触发事件fn.apply(this, offlineStack[key]);}};trigger function () {var key Array.prototype.shift.call(arguments);var fns clientList[key];if (fns) {// 已经有人订阅此事件将参数缓存//假如有些订阅者比较晚订阅且发布者已经发布过了那么这个订阅者订阅的时候自动触发一次订阅内容triggerStack[key] [...arguments];for (var i 0; i fns.length; i) {fns[i].apply(this, arguments);}} else {// 表示当前还没有人订阅此事件则先将参数缓存起来offlineStack[key] [...arguments];}};// 取消订阅remove function (key, fn) {var fns this.clientList[key];if (!fns) {return false;}if (!fn) {// 如果没有传入具体的回调函数表示需要取消 key 对应消息的所有订阅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,};
})();测试1先订阅再发布
// 先订阅
Event.listen(test1, function (a) {console.log(我是发布之前的订阅者1:, a);
});
Event.listen(test1, function (a) {console.log(我是发布之前的订阅者2:, a);
});
// 再发布
Event.trigger(test1, 12);// 我是发布之前的订阅者1: 12
// 我是发布之前的订阅者2: 12测试2先发布再订阅
// 先发布
Event.trigger(test1, 12);// 再订阅
Event.listen(test1, function (a) {console.log(我是发布之后的订阅者1:, a);
});
Event.listen(test1, function (a) {console.log(我是发布之后的订阅者2:, a);
});// 我是发布之后的订阅者1: 12
// 我是发布之后的订阅者2: 12测试3先订阅再发布再订阅
// 先订阅
Event.listen(lis1, function (a) {console.log(我是发布之前的订阅者1:, a);
})
Event.listen(lis1, function (a) {console.log(我是发布之前的订阅者2:, a);
})// 再发布
console.log(---第1次发布);
Event.trigger(lis1, 123);
console.log(---第1次发布完成);// 再订阅
Event.listen(lis1, function (b) {console.log(我是发布之后的订阅者~:, b);
})// ---第1次发布
// 我是发布之前的订阅者1: 123
// 我是发布之前的订阅者2: 123
// ---第1次发布完成
// 我是发布之后的订阅者~: 123测试4先发布再订阅再发布再订阅
// 先发布
console.log(------第1次发布-------);
Event.trigger(lis1, 123);// 再订阅
Event.listen(lis1, function (a) {console.log(我是发布之后的订阅者1:, a);
})
Event.listen(lis1, function (a) {console.log(我是发布之后的订阅者2:, a);
})// 再发布
console.log(------第2次发布-------);
Event.trigger(lis1, 456);// 再订阅
Event.listen(lis1, function (a) {console.log(我是发布之后的再次订阅者1:, a);
})
Event.listen(lis1, function (a) {console.log(我是发布之后的再次订阅者2:, a);
})// ------第1次发布-------
// 我是发布之后的订阅者1: 123
// 我是发布之后的订阅者2: 123// ------第2次发布-------
// 我是发布之后的订阅者1: 456
// 我是发布之后的订阅者2: 456
// 我是发布z之后的再次订阅者1: 456
// 我是发布z之后的再次订阅者2: 456测试5先订阅再发布再订阅再发布
Event.listen(lis1, function (a) {console.log(我是发布之前的订阅者1:, a);
})
Event.listen(lis1, function (a) {console.log(我是发布之前的订阅者2:, a);
})console.log(---第1次发布);
Event.trigger(lis1, 123);
console.log(---第1次发布完成);Event.listen(lis1, function (b) {console.log(我是发布之后的订阅者~:, b);
})console.log(---第2次发布);
Event.trigger(lis1, 456);
console.log(---第2次发布完成);// ---第1次发布
// 我是发布之前的订阅者1: 123
// 我是发布之前的订阅者2: 123
// ---第1次发布完成
// 我是发布之后的订阅者~: 123// ---第2次发布
// 我是发布之前的订阅者1: 456
// 我是发布之前的订阅者2: 456
// 我是发布之后的订阅者~: 456
// ---第2次发布完成6、小结
优点 一为时间上的解耦二为对象之间的解耦
缺点 1、创建订阅者本身要消耗一定的时间和内存而且当你订阅一个消息后也许此消息最后都未发生但这个订阅者会始终存在于内存中 2、如果过度使用的话对象和对象之间的必要联系也将被深埋在背后会导致程序难以跟踪维护和理解
应用 应用非常广泛既可以用在异步编程中也可以帮助我们完成更松耦合的代码编写