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 ответ
Кажется, это ошибка в плагине. Посмотрите на эту линию. Он будет проходить по всем событиям, зарегистрированным на этом канале. Проблема в том, что он останавливается при вызове всех зарегистрированных событий и проверяет длины массива зарегистрированных событий на каждом шаге цикла. Итак, что происходит, это:
- Вы запускаете мероприятие
- Ваше зарегистрированное событие называется
- новый экземпляр создается и регистрируется на канале
- это увеличивает длину массива на один
- поэтому вместо завершения цикла он будет вызывать слушателя только что созданного представления
- вернитесь к 3.
Изменение строки на:
for (var i = 0, l = channels[channel].length; i < l; i++) {
следует исправить это, потому что вы получите длину массива в начале. Добавление нового элемента не заканчивается бесконечным циклом.