JavaScript发布/订阅模式:显示事件链?

JavaScript发布/订阅模式:显示事件链?,javascript,design-patterns,publish-subscribe,Javascript,Design Patterns,Publish Subscribe,假设我使用的是具有高度模块化代码的pub/sub模式。当一个模块中的函数发出“发布”时,我如何弄清楚其他模块中的哪些函数订阅了该触发器 例如: // In module 1 function foo(data) { publish("trigger", data); } // In module 2 function bar(data) {} subscribe("trigger", bar); // In module 3 function baz(data) {} subscr

假设我使用的是具有高度模块化代码的pub/sub模式。当一个模块中的函数发出“发布”时,我如何弄清楚其他模块中的哪些函数订阅了该触发器

例如:

// In module 1
function foo(data) {
    publish("trigger", data);
}

// In module 2
function bar(data) {}
subscribe("trigger", bar);


// In module 3
function baz(data) {}
subscribe("trigger", baz);
在阅读模块1并看到“发布”已发出后,如何知道在我的代码中查找订阅的回调

一个显而易见的解决方案可能是注释哪些模块包含订阅触发器的函数,但在处理大量发布者/订阅者时,这似乎是一个不切实际的解决方案

我觉得我没有完全理解如何使用pub/sub模式,因为在我看来,该模式对于功能链似乎没有任何透明度

编辑

我的问题是让阅读我的源代码的人清楚易懂。我知道在运行时,我可以通过访问存储回调数组,以编程方式找到存储订阅者的列表。但这并不能使我的原始源代码更容易理解

例如,我当前使用的模式如下:

// Main Controller Module
function foo(data) {
    module2.bar();
    module3.bar();
}

// In module 2
function bar(data) {}


// In module 3
function baz(data) {}
首先,本模块的正确术语是什么?我原以为这是一种“中介”模式,但看起来,中介模式更像我所认为的酒吧/酒吧

有了这个模式,我觉得我的代码流是完全透明的。读者不需要到处寻找其他模块foo()中可能调用的函数

但是对于pub/sub模式,一旦我从foo()发出publish,读者就必须找到订阅函数所在的模块

当然,上述模式的缺点是依赖性很强:模块1需要注入模块2和3,然后才能调用bar()和baz()

因此,我希望采用pub/sub模式的松耦合,但我也希望保持上述模式所提供的函数流透明性。这可能吗?或者这只是酒吧/酒吧模式的内在权衡

要修改:


请删除问题。我把这个问题写得很糟糕,我想以更清晰的方式重新提问。谢谢。

我认为发布-订阅或中介的整个想法是松散地耦合对象。Object1不需要知道谁做了它所做的事情,只需要做它自己的事情并通知感兴趣的人它做了它所做的事情

我只在控制器类中注册侦听器,而不是在整个代码中注册侦听器。当控制器需要添加或删除侦听器时,请先通知控制器(为其创建适当的事件),然后分步骤中断流程

例如:

  • 我们使用XHR获取数据
  • 根据我们创建处理器的数据,使用factory创建处理器
  • 处理器处理数据
  • 显示数据
  • 这个过程结束了
  • 在控制器中,您可以有:

    var Controller = {
      //fetch information and display it
      fetch : function(paramObj){
        var subscribeIds = [];
        //to have xhr listen to fetch can be done in an init function
        //  no need to add and remove every time but make a note here
        //  that it's registered in init and part of this process
        subscribeIds.push(Mediator.subscribe(xhr.fetch,"fetch"));
        //xhr will trigger dataFetched
        subscribeIds.push(Mediator.subscribe(Controller.initProsessor,"dataFetched"));
        //Controller will trigger displayFetched
        subscribeIds.push(Mediator.subscribe(dom.displayFetched,"displayFetched"));
        subscribeIds.push(Mediator.subscribe(Controller.displayedFetched,"displayedFetched"));
        paramObj.suscribeIds = subsribeIds;
        Mediator.trigger("fetch",paramObj);
      },
      initProsessor : function(paramObj){
        var processor = Processor.make(paramObj.data.type);
        paramObj.html = processor.process(data);
        Mediator.trigger("displayFetched",paramObj);
      },
      displayedFetched : function(paramObj){
        //You can decide the process is done here or take other steps
        // based on paramObj
        //You can unsubscribe listeners or leave them, when you leave them
        //  they should not be registered in the fetch function but rather
        //  in an init function of Controller with comments saying 
        //  basic fetch procedure
        Controller.cleanupListeners(paramObj.subscribeIds);
      },
      cleanupListeners : function(listenersIds){
        Mediator.unSubscribe(listenersIds);
      }
    }
    
    代码看起来比需要的复杂。看到它的人可能会想,为什么不让XHR创建一个处理器实例并告诉它进行处理呢?原因是,控制器实际上控制着应用程序的流程,如果您希望在两者之间发生其他事情,可以添加它们。随着应用程序的增长,您将添加越来越多的进程,有时会重新考虑函数以完成不太具体的任务,以便更好地重用它们。您现在只需在控制器中重新定义进程,而不必更改多个文件中的代码

    因此,要回答您关于在何处找到侦听器以及在何处注册事件的问题:在控制器中


    如果您有一个中介对象,您可以让它随时转储侦听器,只需编写一个转储方法,该方法将console.log事件名称和函数。toString()。

    假设我正确理解您的代码,此模式的最大优点可能是控制器需要访问您正在注册的所有侦听功能。如果您使用的是AMD模块,则需要将它们注入控制器模块,从而形成一个依赖于一切的大型控制器。这是我目前使用的模式,但我觉得有更好的方法。