RequireJs: неправильный порядок модулей

Я получил следующий router.js:

define(['jquery', 'underscore', 'backbone', 'views/settings/index'], function($, _, Backbone, SettingsView) {

    var Router = Backbone.Router.extend({

        container: $('div.main'),

        routes: {
                "settings": "settings"
                , "settings/:query": "settings"
        },

        settings: function(query) {
            this.container.html(SettingsView.render().el);
        }

    });

    if (Router._instance) return Router._instance;

    Router._instance = new Router();

    return Router._instance;

});

Маршрутизатор вызывается в файле main.js, который помечен как первая зависимость в конфигурации requirejs:

define(['jquery', 'underscore', 'backbone', 'router'], function($, _, Backbone, router) {

    // ajax settings (sent cors cookies)
    $.ajaxSetup({ xhrFields: { withCredentials: true } });

    // register master router
    window.router = router;

    // start backbone history
    Backbone.history.start({ root: "/" });          

});

В некотором смысле я теперь хочу сделать:

define(['jquery', 'underscore', 'backbone', 'router'], function($, _, Backbone, router) {

    var View = Backbone.View.extend({

        initialize: function() {
            router.on('route:settings', this.change, this);
        },

        change: function(query) {
            // load some new content for example
        }

    });

    return View;

});

Чем я получаю это сообщение об ошибке:

Uncaught TypeError: Cannot call method 'on' of undefined 

ОБНОВЛЕНИЕ: я добавил console.log в каждый модуль. Так что я знаю, в каком порядке выполняются модули. Я упомянул, что у requirejs неправильный порядок:

view.js -> main.js -> router.js

вместо:

router.js -> main.js -> view.js

Посмотрим, как я могу это решить

ОБНОВЛЕНИЕ 2: теперь я завернул часть привязки событий маршрутизатора в цикл setTimeout:

        setTimeout(function() {
            window.router.on('route:settings', this.select, this);        
        }.bind(this), 20);

И посмотрите, как это работает!

Это действительно просто исправление, но, тем не менее, исправление :)


person bodokaiser    schedule 31.08.2012    source источник
comment
Честно говоря, я думаю, что вы никоим образом не должны исправлять свою проблему с помощью setTimeout.   -  person robkuz    schedule 01.09.2012


Ответы (3)


Почему вы пытаетесь создать одноэлементный экземпляр на своем маршрутизаторе?

Requirejs разрешает каждый модуль только один раз, насколько я понимаю, и насколько я ожидаю от любого приличного загрузчика модулей.

#router.js
define(['jquery', 'underscore', 'backbone', 'views/settings/index'], 
  function($, _, Backbone, SettingsView) {
  //your code omitted ...

  //no need to do this
  //if (Router._instance) return Router._instance;
  //Router._instance = new Router();
  //return Router._instance;

  //this should work as well and give you a "singleton" instance
  return new Router();

});

person robkuz    schedule 01.09.2012
comment
Вам нужен синглтон, чтобы вы всегда получали один и тот же экземпляр объекта. Магия — это новое ключевое слово ^^ - person bodokaiser; 01.09.2012
comment
Может быть, я был недостаточно ясен. Каждый загруженный модуль будет выполняться только один раз, а результаты (объекты, которые вы возвращаете) будут кэшироваться и использоваться повторно. - person robkuz; 03.09.2012

  1. проверьте правильность имен/путей, которые вы указали для requirejs.config(). Я сильно ударился о стену несколько раз, потому что у меня была небольшая опечатка. requirejs не возвращает никаких ошибок в таких случаях, но, к сожалению, только undefined.
  2. Если вы абсолютно уверены, что нет опечатки, я бы попытался включить main.js как явную зависимость от определения вашего представления.
person robkuz    schedule 01.09.2012
comment
к одному: это не может быть опечаткой. Файл router.js находится непосредственно в корневом каталоге, поэтому ярлык пути отсутствует. Вдвоем: Это действительно хорошая идея! Я попробовал, и, к сожалению, это не сработало. Однако я медленно предполагаю, что у нас есть ошибка - person bodokaiser; 01.09.2012

Я думаю, вам нужно вернуть ссылку на объект Router в конце первого define.

define(['jquery', 'underscore', 'backbone', 'views/settings/index'], function($, _, Backbone, SettingsView) {

    var Router = Backbone.Router.extend({

        container: $('div.main'),

        routes: {
            "settings": "settings"
            , "settings/:query": "settings"
        },

        settings: function(query) {
            this.container.html(SettingsView.render().el);
        }

    });

    var Singletonizer = function(Singleton) {
        if (Singleton._instance) return Singleton._instance;

        Singleton._instance = new Singleton();

        Singletonizer(Singleton);
    };

    return Singletonizer(Router);
});
person Ben    schedule 31.08.2012
comment
Теперь я добавил прослушиватель событий непосредственно в файл, где вызывается маршрутизатор. Там прослушивание событий завершается успешно. В самом представлении я получаю ошибку. Итак, по какой-то причине маршрутизатор недоступен в виде модуля .... - person bodokaiser; 31.08.2012