5

私は現在、Backbone.Mediatorを使用して、Backbone+RequireJSプロジェクトでMediatorPatternの利点を活用しています。しかし、それが「設計による」ものなのか、それともMediator Patternの標準的な動作ではなく、プラグインのバグなのかわからない、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"

ただし、真実は、チャネル'list:switch'をサブスクライブするView2SiblingDivの別のインスタンスであり、作成直後は、チャネル'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. これにより、配列の長さが1つ長くなります
  5. したがって、ループを終了する代わりに、作成したばかりのビューのリスナーを呼び出します
  6. 3に戻ります。

行を次のように変更します。

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

最初に配列の長さを取得するため、これを修正する必要があります。新しい要素を追加しても、無限ループで終了することはありません。

于 2012-09-14T19:39:24.780 に答える