Проблемы RequireJS с доступом к объекту приложения через приложение

У меня есть приложение, в котором есть объект приложения, который выполняет процедуру запуска и хранит полезные вещи, такие как app.state и app.user. Однако я пытаюсь получить доступ к этому экземпляру приложения без передачи this из экземпляра приложения по всей моей большой кодовой базе.

Как ни странно, я работаю над другими проектами, которые включают приложение так же, как и в something.js, и оно работает, но я не понимаю, почему.

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Cannot require app in another file</title>
</head>
<body>
    <script data-main="config" src="require.js"></script>
</body>
</html>

config.js

requirejs.config({
    deps: ['app']
});

app.js

define([
    'something'
], function(Something) {
    'use strict';

    var App = function() {
        this.name = 'My app';
    };

    return new App();
});

что-то.js

define([
    'require',
    'app'
], function (require, app) {
    'use strict';

    var SomeModule = function() {
        app = require('app'); // EXCEPTION
        console.log('App:', app);
    };

    return new SomeModule();
});

При загрузке этого исключения requirejs возникает из-за требования в SomeModule:

Необработанная ошибка: имя модуля "приложение" еще не загружено для контекста: _

Демонстрация выше (ошибки см. в консоли): http://dominictobias.com/circulardep/


person Dominic    schedule 17.05.2014    source источник


Ответы (1)


Мне непонятно, зачем вам нужна круговая зависимость. Как указано в документации для RequireJS:

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

При этом, если вам нужна циклическая зависимость, проблема с вашим кодом заключается в том, что require('app') вызывается слишком рано. Его нельзя вызвать, пока после модуль something не вернет свое значение. Прямо сейчас он вызывается до возврата значения. Если вы посмотрите на код, приведенный в качестве примера в документации:

define(["require", "a"],
    function(require, a) {
        //"a" in this case will be null if a also asked for b,
        //a circular dependency.
        return function(title) {
            return require("a").doSomething();
        }
    }
);

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

Итак, как это исправить? Что вы можете сделать, так это заставить класс, который вы возвращаете, вызывать функцию, которая извлекает модуль app всякий раз, когда это необходимо. Так:

define([
    'require',
    'app'
], function (require) {
    'use strict';

    var app_;
    function fetch_app() {
        if (app_ === undefined)
            app_ = require("app");
        return app_;
    }

    var SomeModule = function() {
        // ...
    };

    SomeModule.prototype.doSomethingWithApp = function () {
        var app = get_app();
        app.whatever();
    };

    return new SomeModule();
});

Я удалил app из списка аргументов и сохранил значение модуля app в app_, потому что это обеспечивает раннее обнаружение отсутствующего вызова get_app() в любом методе SomeModule. Если app сделать параметром фабричной функции модуля, то использование app внутри метода без предварительного вызова get_app() будет обнаружено только в том случае, если так случилось, что никакой другой метод, вызывающий get_app(), не был вызван первым. (Конечно, я мог бы набрать app_ и столкнуться с той же проблемой, которую я стремлюсь предотвратить. Это вопрос соответствующих вероятностей: очень вероятно, что я забуду вызвать get_app() везде, где это необходимо. потому что я обычно не пишу код с циклическими зависимостями.Однако я бы вряд ли набрал app_ вместо app, потому что я обычно не ставлю _ в конце имен переменных.)

person Louis    schedule 17.05.2014
comment
Спасибо за подробный ответ. Я думал о том, что вы/документы говорите о циклическом отделении, и я думаю, что я только что перенял эту плохую практику из другого приложения, не задумываясь об этом - вы правы, мне не нужно делать этот круговой цикл ради доступа некоторые прикрепленные объекты, которые я мог бы просто потребовать там, где это необходимо. - person Dominic; 18.05.2014
comment
Да, избавление от циклической зависимости значительно упростит задачу. - person Louis; 18.05.2014
comment
Подводя итог для читателей: вы в принципе не можете требовать в приложении для new зависимостей во время процедуры инициализации. - person Dominic; 19.05.2014