5

我目前正在使用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"

然而,事实是因为View2SiblingDiv的另一个实例订阅了 Channel 'list:switch',在它创建之后,它也会被仍然在 Channel 'list:switch' 上传递的事件信号触发(它只会在)的执行。SiblingDiv**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();
        }
    });
});

但是我很想了解无限循环行为(在事件信号广播期间创建的新对象也将由该信号触发)是否被认为是调解器模式方法中的“标准”?或者这只是插件部分的一个错误?

4

1 回答 1

4

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

  1. 你触发了这个事件
  2. 您注册的事件被称为
  3. 创建一个新实例并将其自身注册到通道
  4. 这会将数组的长度增加一
  5. 所以它不会结束循环,而是调用刚刚创建的视图的监听器
  6. 回到 3。

将行更改为:

for (var i = 0, l =  channels[channel].length; i < l; i++) {

应该解决这个问题,因为您在开始时获得了数组的长度。添加新元素不会以无限循环结束。

于 2012-09-14T19:39:24.780 回答