Backbone + RequireJS + Mediator Pattern导致View Logic短路和无限循环

gsk*_*lee 5 javascript design-patterns mediator requirejs backbone.js

我目前正在使用Backbone.Mediator在我的Backbone + RequireJS项目中利用Mediator Pattern的好处; 然而,我遇到了一个模式的特殊行为,不太确定它是"按设计",或者更确切地说,不是Mediator Pattern的标准行为,而是插件中的错误.

作为一个人为的例子:

AMD模块1

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

AMD模块2

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

return View2;
Run Code Online (Sandbox Code Playgroud)

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();
        }
    });
});
Run Code Online (Sandbox Code Playgroud)

我以为它会像这样工作:

                      **View1**.switchList();
                      ?
Channel 'list:switch' ?
                      ?
                      **View2**.shrinkDiv();
                      ?
                      ???
                      ? ? Channel 'div:shrink'
                      ? ?
                      ? **View3**.createSiblingDiv();
                      ? ?
                      ? ???? "SiblingDiv created and rendered"
                      ?
                      ?????? "View2 Div shrinked and more"
Run Code Online (Sandbox Code Playgroud)

然而,事实是因为View2的SiblingDiv另一个实例是订阅频道'list:switch',在创建之后,也会被仍然通过频道列表发生的事件信号触发: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"
Run Code Online (Sandbox Code Playgroud)

无限循环...哎呀!

通过对代码的一些修改,我能够按照自己的方式工作:

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;
Run Code Online (Sandbox Code Playgroud)

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();
        }
    });
});
Run Code Online (Sandbox Code Playgroud)

但我非常有兴趣了解无限循环行为(事件信号广播期间创建的新对象是否也将由该信号触发)在Mediator Pattern方法中被视为"标准"?或者这只是插件部分的一个错误?

And*_*rle 4

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

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

将行更改为:

for (var i = 0, l =  channels[channel].length; i < l; i++) {
Run Code Online (Sandbox Code Playgroud)

应该修复这个因为你在开始时得到数组的长度.添加新元素不会以无限循环结束.