Подтвердить что ты не робот

Лучшая практика для общих объектов в 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

Если вы читаете это далеко, вы потрясающий! Спасибо, что нашли время.

4b9b3361

Ответ 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 строк.

Это упрощает запись модульных тестов для кода вида. Так как вы могли бы пройти поддельные модели в своих тестах.