本文共 3174 字,大约阅读时间需要 10 分钟。
发布-订阅模式(Observer Pattern)是一种常见的设计模式,主要用于处理对象间的一对多关系。当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知。这种模式在异步编程中尤为重要,能够有效替代传递回调函数的方式,使代码更加松耦合。
在前言中提到,DOM事件可以被看作是发布-订阅模式的简单实现。每当在DOM节点上绑定事件时,就相当于创建了一个发布-订阅关系。当事件发生时,所有绑定的回调函数都会被调用。
此外,自定义事件是实现发布-订阅模式的重要工具。通过自定义事件,我们可以在任何JavaScript代码中灵活地管理事件传播。
要实现发布-订阅模式,可以按照以下步骤进行:
salesOffices)作为发布者。listen方法将自己的回调函数添加到缓存列表中。trigger方法遍历缓存列表,调用所有订阅者的回调函数。为了提高效率,可以在回调函数中添加标识符,确保订阅者只接收感兴趣的消息。例如,小明只订阅88平方米的房子信息,而不需要处理110平方米的消息。
在一个商城网站中,header、nav、消息列表等模块需要获取用户的登录信息。为了实现这一目标,我们可以使用发布-订阅模式:
loginSucc事件。listen方法订阅loginSucc事件,分别处理登录信息。为了实现模块间通信,可以基于一个全局的Event对象:
// 全局Event对象var Event = { clientList: {}, listen: function(key, fn) { if (!Event.clientList[key]) { Event.clientList[key] = []; } Event.clientList[key].push(fn); }, trigger: function() { var key = Array.prototype.shift.call(arguments); var fns = Event.clientList[key]; if (!fns || fns.length === 0) { return false; } for (var i = 0; i < fns.length; i++) { fns[i].apply(this, arguments); } }};// 模块A订阅事件Event.listen('add', function(count) { console.log('点击次数:', count);});// 模块B订阅事件Event.listen('add', function(count) { document.getElementById('show').innerHTML = count;});// 模块A触发事件button.onclick = function() { Event.trigger('add', count);}; 在实际应用中,有时候发布事件的对象在订阅事件的对象尚未准备好。这种情况下,可以采用先保存事件再发布的方式:
// 保存事件eventStack.push(function() { Event.trigger('saveData');});// 发布事件Event.trigger('saveData'); 这种方式类似于QQ的离线消息处理,确保即使发布者尚未订阅事件,事件也能在适当的时候被处理。
为了避免全局事件名冲突,可以为事件创建命名空间:
var Event = (function() { var namespaces = {}, clientList = {}, listen = function(key, fn) { if (!namespaces[key]) { namespaces[key] = { clientList: [] }; } namespaces[key].clientList.push(fn); }; var trigger = function() { var key = Array.prototype.shift.call(arguments); var ns = key.split('.').shift(); var clientList = namespaces[ns] ? namespaces[ns].clientList : []; if (!clientList || clientList.length === 0) { return false; } for (var i = 0; i < clientList.length; i++) { clientList[i].apply(this, arguments); } }; return { create: function(namespace) { namespaces[namespace] = { clientList: [] }; return { listen: function(key, fn) { listen(key, fn, namespace); }, trigger: function() { trigger.apply(this, arguments, namespace); } }; } };})();Event.create('namespace1').listen('click', function(a) { console.log(a);});Event.create('namespace2').listen('click', function(a) { console.log(a);});Event.create('namespace1').trigger('click', 1);Event.create('namespace2').trigger('click', 2); 发布-订阅模式是一种强大的设计模式,能够有效地处理对象间的松耦合通信。在实际应用中,可以通过全局Event对象实现模块间通信,确保各模块保持高度封装。同时,通过命名空间管理,可以有效避免全局事件名冲突,提升代码的可维护性和扩展性。
转载地址:http://edouz.baihongyu.com/