我目前正在使用Backbone.Mediator在Backbone + RequireJS项目中利用Mediator Pattern的好处;但是,我遇到了Pattern的特殊行为,不能确定它是“按设计”生成的,还是不确定Mediator Pattern的标准行为,而是插件中的错误。

举一个人为的例子:

AMD模块1

var View1 = Backbone.View.extend({
    ...
    events: {
        'click div: switchList'
    },
    switchList: function() {
        Backbone.Mediator.pub('list:switch');
    }
});

AMD模块2
var View2 = Backbone.View.extend({
    ...
    subscriptions: {
        'list:switch': 'shrinkDiv'
    },
    shrinkDiv: function() {
        Backbone.Mediator.pub('div:shrink');
        this.shrinkAndMore();
    }
});

return View2;

AMD模块3
define(function(require) {
    var View2 = require(**AMD Module 2**);

    var View3 = Backbone.View.extend({
        ...
        subscriptions: {
            'div:shrink': 'createSiblingDiv'
        },
        createSiblingDiv: function() {
            this.siblingView = new View2();
            this.$el.after(this.siblingView.$el);
            this.siblingView.render();
        }
    });
});

我认为它会像这样工作:
                      **View1**.switchList();
                      │
Channel 'list:switch' │
                      ↓
                      **View2**.shrinkDiv();
                      │
                      ├─┐
                      │ │ Channel 'div:shrink'
                      │ ↓
                      │ **View3**.createSiblingDiv();
                      │ │
                      │ └──→ "SiblingDiv created and rendered"
                      │
                      └────→ "View2 Div shrinked and more"

但是,事实是,因为SiblingDiv View2 的另一个实例,它订阅了 channel “list:switch”,所以SiblingDiv在创建后立即也会由仍然在 channel “list:switch”上发生的事件信号触发(只会在**View2**.shrinkAndMore();执行之后停止。

因此,实际的代码流如下所示:
                      **View1**.switchList();
                      │
Channel 'list:switch' │
                      ↓
                      **View2**.shrinkDiv(); ←──────────────────┐
                      │                                         │
                      ├─┐                                       │
                      │ │ Channel 'div:shrink'                  │
                      │ ↓                                       │
                      │ **View3**.createSiblingDiv();           │
                      │ │                                       │
                      │ └──→ "SiblingDiv created and rendered" ─┘
                      │
                      └────→ "View2 Div shrinked and more"

无限循环...糟糕!

通过对代码进行一些修改,我可以使事情正常进行:

AMD模块2修改后的
var View2 = Backbone.View.extend({
    initialize: function() {                                 // new code
        if (this.options.subscriptions) {                    // new code
            this.subscriptions = this.options.subscriptions; // new code
        }                                                    // new code
    },                                                       // new code
    ...
    subscriptions: {
        'list:switch': 'shrinkDiv'
    },
    shrinkDiv: function() {
        Backbone.Mediator.pub('div:shrink');
        this.shrinkAndMore();
    }
});

return View2;

AMD模块3修改后的
define(function(require) {
    var View2 = require(**AMD Module 2**);

    var View3 = Backbone.View.extend({
        ...
        subscriptions: {
            'div:shrink': 'createSiblingDiv'
        },
        createSiblingDiv: function() {
            this.siblingView = new View2({        // new code
                subscriptions: {}                 // new code
            });                                   // new code
            this.$el.after(this.siblingView.$el);
            this.siblingView.render();
        }
    });
});

但是,我很感兴趣地了解,在Mediator Pattern方法中,是否将无限循环行为(在期间在事件信号广播中创建的新对象也会触发该信号)视为“标准”?还是这仅仅是插件部分的错误?

最佳答案

似乎这是插件中的错误。看一看this line。它将遍历此 channel 中注册的所有事件。问题在于,它会在调用每个已注册事件时停止,并且会在每个循环步骤中检查已注册事件数组的长度。所以发生的是:

  • 您触发事件
  • 您注册的事件称为
  • 创建一个新实例并将其自身注册到
  • channel
  • 将数组的长度增加一个
  • ,而不是结束循环,它将调用刚创建的 View
  • 的监听器
  • 回到3。

  • 将行更改为:
    for (var i = 0, l =  channels[channel].length; i < l; i++) {
    

    应该可以解决此问题,因为您可以从一开始就获得数组的长度。添加新元素不会在无限循环中结束。

    10-02 03:14
    查看更多