Backbone + RequireJS + Mediator Pattern привел к короткому замыканию View Logic и бесконечному циклу

В настоящее время я использую Backbone.Mediator, чтобы использовать преимущества Mediator Pattern в моем проекте Backbone + RequireJS; Тем не менее, я столкнулся со странным поведением Pattern, которое не вполне уверено, является ли это "by-design", или, скорее, не стандартным поведением 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 Module 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сразу после его создания также будет вызван сигналом события, все еще проходящим по каналу "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 Module 2 Modded

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 Module 3 Modded

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();
        }
    });
});

Но мне очень интересно понять, считается ли поведение бесконечного цикла (новый Объект, созданный во время трансляции сигнала события, также вызванным этим сигналом) считающимся "стандартным" в методологии "Шаблон посредника"? Или это просто ошибка в плагине?

1 ответ

Решение

Кажется, это ошибка в плагине. Посмотрите на эту линию. Он будет проходить по всем событиям, зарегистрированным на этом канале. Проблема в том, что он останавливается при вызове всех зарегистрированных событий и проверяет длины массива зарегистрированных событий на каждом шаге цикла. Итак, что происходит, это:

  1. Вы запускаете мероприятие
  2. Ваше зарегистрированное событие называется
  3. новый экземпляр создается и регистрируется на канале
  4. это увеличивает длину массива на один
  5. поэтому вместо завершения цикла он будет вызывать слушателя только что созданного представления
  6. вернитесь к 3.

Изменение строки на:

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

следует исправить это, потому что вы получите длину массива в начале. Добавление нового элемента не заканчивается бесконечным циклом.

Другие вопросы по тегам