8

我目前正在开发我的第一个backbone.js 应用程序。事件的概念对我来说非常熟悉,但我是否应该使用中央事件调度程序存在疑问。通常我看到这两种方法:

  • 直接将事件发布者和事件接收者连接在一起。(我从这种方法开始。)
  • 使用事件总线并将发布者和接收者连接到该总线。

就应用程序的长期可维护性和事件的可追溯性而言,使用事件总线是否有利?

4

1 回答 1

13

应根据具体情况评估是使用中央事件总线还是直接将事件连接在一起。根据情况,有时您会偏爱其中一个。

由于发布者和接收者没有紧密耦合,我将尽可能使用中央事件总线。在我看来,这使您的代码更易于维护和灵活。

当您有以下情况时,我发现中央事件总线非常有用:

  1. 单个事件发布实例和众多事件接收器。
  2. 许多事件发布实例和单个事件接收器

当事件接收器实例或发布器实例是动态的并且因此在应用程序的生命周期内被创建和销毁时,在上述情况下中央事件总线的好处变得更加明显。例如,考虑以下单页应用程序:

  1. 单页应用程序必须拉伸以适应浏览器窗口的宽度。
  2. 单页应用程序主要是一组选项卡式视图,但是选项卡的数量是动态的,因为它们是由用户创建和销毁的
  3. 选项卡的内容都是不同的,除了它们有一个主要的内容区域,在考虑其他同级元素的宽度后,必须拉伸以适应可用宽度
  4. 由于选项卡的内容不断变化,因此需要在许多不同的点调整大小。

在上述情况下,无论具体场景如何,中央总线模型都非常有效。一个代码示例是:

应用层

var App = {

    init: function () {
        // Event to resize width of element to remaining width
        App.Events.on("fitRemainingWidth:app", this.fitRemainingWidth);
     },

    // event pub sub for the app.
    Events: _.extend({}, Backbone.Events),

    // function that expands an element, or elements to the remaining width in the window. 
    fitRemainingWidth: function(targetEls) {
        var els = $(targetEls);
        _.each(els, function (e) {
            var el = $(e);
            var cont = el.parent();
            newWidth = cont.innerWidth();
            otherElements = cont.children().not(el);
            otherElementsWidth = 0;

            otherElements.each(function () {
                otherElementsWidth += $(this).outerWidth();
            });

            el.width(newWidth - otherElementsWidth);
        });
    }
}

在你看来

每当需要调整某物的大小时,您都会触发该事件,例如:

App.Events.trigger("fitRemainingWidth:app", this.$(".main-content"), this);

正如你所看到的,这真的很有用,因为 fitRemainingWidth 函数可以应用于任何东西,你永远不知道将来哪些视图可能想要使用它,或者什么时候需要调用它。

所以我想当我发现不使用中央事件总线更可取时,我应该继续前进。我确信还有其他情况,但对我来说主要的情况是接收器需要连接到发布者的特定实例。例如,如果我们继续使用选项卡式应用程序示例,假设每个选项卡的内容是特定人员邮箱的拆分视图。在每个拆分视图中都有一个显示电子邮件集合的列表窗格和一个显示列表中当前选定邮件内容的阅读窗格。

在这种情况下,我们希望在单击电子邮件时触发“selected:email”事件,并将相应的阅读窗格绑定到它,以便它可以显示电子邮件的内容。

假设我们打开了十个邮箱选项卡,每个选项卡都有自己的电子邮件列表窗格和阅读窗格。这就产生了十个电子邮件列表和十个阅读窗格。如果我在从其中一个列表中触发“selected:email”时在这种情况下使用中央事件总线,则从事件总线接收这些事件的阅读窗格需要有自己的智能来尝试和工作确定所选电子邮件是否是他们需要显示的内容。每个阅读窗格都尝试解决这个问题并不是真正可取的,并且涉及到不必要的逻辑。对于阅读窗格来说,接收带有电子邮件对象的“selected:email”事件作为有效负载并显示它要好得多。

因此,在这种情况下,最好让每个邮箱选项卡视图负责连接其特定子视图实例及其模型和集合的事件。在我们的示例中,这意味着电子邮件列表视图的特定实例及其集合和阅读窗格视图的特定关联实例。

总而言之,我建议每种情况都有用例,并且您应该为遇到的每种情况谨慎选择正确的方法。两者都使用,并学会看看什么适合什么情况。

最后,关于事件的可追溯性,您始终可以为事件总线中的OnandOff函数编写一个包装器,它既调用正常的OnOff函数,也将信息添加/删除到包含哪些对象绑定到哪些事件的寄存器中。您可以使用它进行调试并将有关这些对象的信息写入控制台,以便您可以清楚地了解事件总线及其侦听器在任何时间点的状态。我从来没有想过这样做,但你没有理由不能这样做;)

帖子编辑: tsiki 关于使用本地事件总线的评论是一个很好的评论。在上面我使用许多选项卡式邮箱制作的示例中,您可以为每个用户邮箱选项卡视图使用本地事件总线。如果每个邮箱选项卡视图本身变得相当复杂,包含许多嵌套子视图和大量要生成/处理的事件,您可能希望这样做。

于 2013-06-03T05:18:03.497 回答