Лучшая практика для общих объектов в Backbone/Require Application
Я разрабатываю Backbone-приложения на некоторое время, и только начинаю учиться использовать Backbone с Require.js.
В моем базовом приложении, которое я рефакторинг, я определил пространство имен, подобное этому: App.model.repo
. Эта модель используется снова и снова в разных представлениях. Я делаю то же самое с несколькими коллекциями, например, App.collection.files
. Эти модели и коллекции загружаются с исходным запросом файла индекса.
Я нашел этот пример, который выглядит как отличный способ получить эти загрузочные данные. Однако я изо всех сил стараюсь использовать их повторно моделей и коллекции между представлениями.
Я могу думать о трех возможных решениях. Что лучше и почему? Или есть другое решение, которое я полностью потерял?
Решение 1
Определите эти общие модули и коллекции в индексе (когда они загружаются), а затем передайте их каждому представлению Backbone в качестве опции (initialize
).
define(['jquery', 'underscore', 'backbone', 'handlebars', 'text!templates/NavBar.html'],
function($, _, Backbone, Handlebars, template){
return Backbone.View.extend({
template: Handlebars.compile(template),
initialize: function(options){
this.repoModel = options.repoModel; // common model passed in
}
});
}
);
Они кажутся чистыми до разделения, но могут быстро стать напуганными, и тонны вещей передаются повсюду.
Решение 2
Определите модуль globals
и добавьте к нему обычно используемые модели и коллекции.
// models/Repo.js
define(['backbone'],
function(Backbone){
return Backbone.Model.extend({
idAttribute: 'repo_id'
});
}
);
// globals.js (within index.php, for bootstrapping data)
define(['underscore', 'models/Repo'],
function(_, RepoModel){
var globals = {};
globals.repoModel = new Repo(<?php echo json_encode($repo); ?>);
return globals
}
);
define(['jquery', 'underscore', 'backbone', 'handlebars', 'text!templates/NavBar.html', 'globals'],
function($, _, Backbone, Handlebars, template, globals){
var repoModel = globals.repoModel; // repoModel from globals
return Backbone.View.extend({
template: Handlebars.compile(template),
initialize: function(options){
}
});
}
);
Означает ли это решение всю цель AMD?
Решение 3
Сделайте несколько моделей и коллекций, возвращающих экземпляр вместо конструктора (эффективно создавая синглтоны).
// models/repo.js
define(['backbone'],
function(Backbone){
// return instance
return new Backbone.Model.extend({
idAttribute: 'repo_id'
});
}
);
// Included in index.php for bootstrapping data
require(['jquery', 'backbone', 'models/repo', 'routers/Application'],
function($, Backbone, repoModel, ApplicationRouter){
repoModel.set(<?php echo json_encode($repo); ?>);
new ApplicationRouter({el: $('.site-container')});
Backbone.history.start();
}
);
define(['jquery', 'underscore', 'backbone', 'handlebars', 'text!templates/NavBar.html', 'models/repo'],
function($, _, Backbone, Handlebars, template, repoModel){
// repoModel has values set by index.php
return Backbone.View.extend({
template: Handlebars.compile(template),
initialize: function(options){
}
});
}
);
Это, я беспокоюсь, может смутить насчет того, что такое конструктор и что такое экземпляр.
End
Если вы читаете это далеко, вы потрясающий! Спасибо, что нашли время.
Ответы
Ответ 1
В моем случае я предпочитаю вариант 3. Хотя, чтобы предотвратить путаницу, я помещаю каждый экземпляр singleton в свою собственную папку с именем instances
. Кроме того, я склонен отделять model/collection
от модуля instance
.
Затем я просто назову их:
define([
"instance/photos"
], function( photos ) { /* do stuff */ });
Я предпочитаю эту опцию, так как каждый модуль вынужден определять свои зависимости (например, это не относится к пространству имен). Решение 2 могло бы выполнить эту работу, но если я использую AMD, я хочу, чтобы мой модуль был как можно меньшим, а также не уменьшая их до уровня unit test.
И, наконец, о unit test, я могу просто переопределить экземпляр внутри моего unit test, чтобы использовать mock-данные. Итак, определенно, вариант 3.
Вы можете увидеть пример этого шаблона в приложении с открытым исходным кодом, над которым я работаю в банкомате: https://github.com/iplanwebsites/newtab-bookmarks/tree/master/app
Ответ 2
Я бы посмотрел на этот пример repo https://github.com/tbranyen/github-viewer
Это рабочий пример магистральной котла пластины (https://github.com/tbranyen/backbone-boilerplate)
Базовая плита котла делает много ненужного пуха, но то, что действительно полезно в этом, заключается в том, что он дает некоторые четкие указания по общим шаблонам для разработки сложных приложений javascript.
Я попробую и вернусь позже сегодня, чтобы ответить на ваш вопрос более конкретно (если кто-то не избил меня до этого:)
Ответ 3
Я предпочитаю решение 1. Обычно полезно избегать используя singletons, а также использовать глобальные переменные также можно избежать, тем более, что вы используете RequireJS.
Вот некоторые преимущества, которые я могу придумать для решения 1:
Это делает код просмотра более читаемым. Кто-то, смотрящий на модуль в первый раз, может сразу увидеть, глядя на функцию initialize
, которая моделирует ее. Если вы используете глобальные переменные, к файлу может быть доступно 500 строк.
Это упрощает запись модульных тестов для кода вида. Так как вы могли бы пройти поддельные модели в своих тестах.