博客
关于我
《JavaScript设计模式与开发实践》笔记第八章 发布-订阅模式
阅读量:429 次
发布时间:2019-03-06

本文共 3095 字,大约阅读时间需要 10 分钟。

发布-订阅模式:从基础到实践

发布-订阅模式(Observer Pattern)是一种常见的设计模式,主要用于处理对象间的一对多关系。当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知。这种模式在异步编程中尤为重要,能够有效替代传递回调函数的方式,使代码更加松耦合。

发布-订阅模式的核心优势

  • 松耦合性:发布者和订阅者之间不需要直接耦合,只需通过事件名称进行通信。
  • 灵活性:订阅者可以随时加入或退出,无需修改发布者的代码。
  • 异步性:适合处理异步操作,避免了回调链的复杂性。
  • DOM事件与自定义事件

    在前言中提到,DOM事件可以被看作是发布-订阅模式的简单实现。每当在DOM节点上绑定事件时,就相当于创建了一个发布-订阅关系。当事件发生时,所有绑定的回调函数都会被调用。

    此外,自定义事件是实现发布-订阅模式的重要工具。通过自定义事件,我们可以在任何JavaScript代码中灵活地管理事件传播。

    优雅实现发布-订阅模式

    要实现发布-订阅模式,可以按照以下步骤进行:

  • 指定发布者:通常选择一个专门的对象(如salesOffices)作为发布者。
  • 维护订阅列表:在发布者对象中创建一个缓存列表,存储所有订阅者的回调函数。
  • 订阅事件:订阅者通过listen方法将自己的回调函数添加到缓存列表中。
  • 发布事件:发布者通过trigger方法遍历缓存列表,调用所有订阅者的回调函数。
  • 为了提高效率,可以在回调函数中添加标识符,确保订阅者只接收感兴趣的消息。例如,小明只订阅88平方米的房子信息,而不需要处理110平方米的消息。

    实际应用案例

    网站登录示例

    在一个商城网站中,header、nav、消息列表等模块需要获取用户的登录信息。为了实现这一目标,我们可以使用发布-订阅模式:

  • 登录信息发布:通过AJAX调用登录接口,获取用户数据后,触发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/

    你可能感兴趣的文章
    Postman被低估的功能 — 自动化接口测试
    查看>>
    Postman被低估的功能 — 自动化接口测试
    查看>>
    Postman轻松签名,让SHA256withRSA保驾护航
    查看>>
    Postman还能做Mock?又学了一招!
    查看>>
    Postman还能做Mock?又学了一招!
    查看>>
    postman进行http接口测试
    查看>>
    Postman高阶技能:Collection集合批量运行!
    查看>>
    postMessage跨标签页共享数据
    查看>>
    QImage对一般图像的处理
    查看>>
    post为什么会发送两次请求?
    查看>>
    Post表单提交TextArea的值出现转译乱码问题 - Spring MVC处理表单提交
    查看>>
    Power BI 中的 Python 可视化需要什么设置?任何特定的 matplotlib 包版本或系统设置?
    查看>>
    Power BI:如何在 Power Query 编辑器中将 Python 与多个表一起使用?
    查看>>
    power english (3) main text -emotion mastery - focus
    查看>>
    POWER ENGLISH (6) - MODEL
    查看>>
    power english (1) —— passion
    查看>>
    Power English (1) 原文
    查看>>
    power English (3)原文
    查看>>
    POWER ENGLISH(7)- repetition
    查看>>
    SpringBoot中集成SpringBatch详细解析与实战示例(CSV文件读取十万条数据进行业务处理后写入Mysql数据库)
    查看>>