Angularjs 依赖项的角度执行顺序

Angularjs 依赖项的角度执行顺序,angularjs,requirejs,Angularjs,Requirejs,我最近将我的项目从通过ng app默认方法引导angular转换为使用RequireJs并手动执行。大多数情况下,一切都正常工作,但在某些情况下,我会收到错误消息,说登录页面的控制器和服务未定义,因此控制器未正确加载,值未绑定 我相信问题源于依赖项的执行顺序。首先,以下是错误: 错误:[ng:areq] 错误:[$injector:unpr]$injector/unpr?p0=UsersServiceProvider%20%3C-%20UsersService%20%3C-%20LoginCon

我最近将我的项目从通过ng app默认方法引导angular转换为使用RequireJs并手动执行。大多数情况下,一切都正常工作,但在某些情况下,我会收到错误消息,说登录页面的控制器和服务未定义,因此控制器未正确加载,值未绑定

我相信问题源于依赖项的执行顺序。首先,以下是错误:

错误:[ng:areq]

错误:[$injector:unpr]$injector/unpr?p0=UsersServiceProvider%20%3C-%20UsersService%20%3C-%20LoginController

到目前为止,我只在Chrome中看到这个问题,当我打开javascript控制台时,一切似乎都正常。我插入了几个console.log()语句,以了解这些脚本中的活动顺序。对于三个文件,routeConfig.js、nav.js和usersService.js,定义函数的第一行有一个console.log,角度定义函数的第一行有一个console.log:

routeConfig.js:

define(['angularAMD',
        'angular-route',
        'uiBootstrap',
        'lib/angularSlideables',
        'lib/ng-infinite-scroll',
        'lib/angular-modal-service'], function (angularAMD) {

    console.log('top of routeConfig');

    var app = angular.module('svlPlatform', ['ngRoute', 'ui.bootstrap', 'angularSlideables', 'infinite-scroll', 'angularModalService']).value('THROTTLE_MILLISECONDS', 750);

    app.config(['$routeProvider', function ($routeProvider, $httpProvider) {

        console.log('inside routeConfig');

        //  Because angularAMD is built on requireJS, the following paths to controllerUrl follow requireJs's conventions.
        //  They don't need a .js extention and they are relative to the baseUrl specified in require.config.
        $routeProvider
            .when('/login', angularAMD.route({
                templateUrl: 'views/login.html',
                controllerUrl: 'controllers/login'
            }))
            .when('/me', angularAMD.route({
                templateUrl: 'views/me.html',
                controllerUrl: 'controllers/me'
            }))   //this continues and returns app...
define(['config/routeConfig', 'services/authService', 'services/usersService', 'services/menuService'], function(app) {

    console.log('top of nav controller');

    app.controller('NavController', ['$log', '$anchorScroll', '$location', '$rootScope', 'AuthService', 'UsersService', 'MenuService',
        function ($log, $anchorScroll, $location, $rootScope, auth, users, menu) {

        console.log('inside nav controller');

            var vm = this;
            menuScope = this;

            function loadMenu() {
                menu.items().then(function(response){
                    vm.menuItems = response.data.menuItems;
                    $('body').css("background-color","#f2f2f2");
                    markMenuActive(vm.menuItems);
                }, function(error) {
                    console.log('There was a problem getting the menu data.');
                });
            }   //continues...
require.config({
    baseUrl: 'javascripts',
    paths: {
        'angular': '//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min',
        'angular-route': '//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-route.min',
        'bootstrapJs': '//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min',
        'uiBootstrap': '//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.1/ui-bootstrap-tpls.min',
        'angularAMD': '//cdn.jsdelivr.net/angular.amd/0.2.0/angularAMD.min'
    },
    shim: {
        'angularAMD': ['angular'],
        'bootstrapJs': [],
        'uiBootstrap': ['angular'],
        'lib/angularSlideables': ['angular'],
        'lib/ng-infinite-scroll': ['angular'],
        'angular-route': ['angular'],
        'lib/angular-modal-service': ['angular']
    },
    deps: [
        'bootstrapJs',
        'config/routeConfig',
        'services/authService',
        'services/usersService',
        'services/menuService',
        'controllers/nav',
        'controllers/main',
        'lib/angular-modal-service',
        'config/config',
        'app'
    ]
});
nav.js:

define(['angularAMD',
        'angular-route',
        'uiBootstrap',
        'lib/angularSlideables',
        'lib/ng-infinite-scroll',
        'lib/angular-modal-service'], function (angularAMD) {

    console.log('top of routeConfig');

    var app = angular.module('svlPlatform', ['ngRoute', 'ui.bootstrap', 'angularSlideables', 'infinite-scroll', 'angularModalService']).value('THROTTLE_MILLISECONDS', 750);

    app.config(['$routeProvider', function ($routeProvider, $httpProvider) {

        console.log('inside routeConfig');

        //  Because angularAMD is built on requireJS, the following paths to controllerUrl follow requireJs's conventions.
        //  They don't need a .js extention and they are relative to the baseUrl specified in require.config.
        $routeProvider
            .when('/login', angularAMD.route({
                templateUrl: 'views/login.html',
                controllerUrl: 'controllers/login'
            }))
            .when('/me', angularAMD.route({
                templateUrl: 'views/me.html',
                controllerUrl: 'controllers/me'
            }))   //this continues and returns app...
define(['config/routeConfig', 'services/authService', 'services/usersService', 'services/menuService'], function(app) {

    console.log('top of nav controller');

    app.controller('NavController', ['$log', '$anchorScroll', '$location', '$rootScope', 'AuthService', 'UsersService', 'MenuService',
        function ($log, $anchorScroll, $location, $rootScope, auth, users, menu) {

        console.log('inside nav controller');

            var vm = this;
            menuScope = this;

            function loadMenu() {
                menu.items().then(function(response){
                    vm.menuItems = response.data.menuItems;
                    $('body').css("background-color","#f2f2f2");
                    markMenuActive(vm.menuItems);
                }, function(error) {
                    console.log('There was a problem getting the menu data.');
                });
            }   //continues...
require.config({
    baseUrl: 'javascripts',
    paths: {
        'angular': '//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min',
        'angular-route': '//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-route.min',
        'bootstrapJs': '//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min',
        'uiBootstrap': '//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.1/ui-bootstrap-tpls.min',
        'angularAMD': '//cdn.jsdelivr.net/angular.amd/0.2.0/angularAMD.min'
    },
    shim: {
        'angularAMD': ['angular'],
        'bootstrapJs': [],
        'uiBootstrap': ['angular'],
        'lib/angularSlideables': ['angular'],
        'lib/ng-infinite-scroll': ['angular'],
        'angular-route': ['angular'],
        'lib/angular-modal-service': ['angular']
    },
    deps: [
        'bootstrapJs',
        'config/routeConfig',
        'services/authService',
        'services/usersService',
        'services/menuService',
        'controllers/nav',
        'controllers/main',
        'lib/angular-modal-service',
        'config/config',
        'app'
    ]
});
usersService.js

define(['config/routeConfig', 'utils/urlBuilder', 'services/menuService'], function (app, _urlBuilder) {

    console.log('top of users service');

    var urlBuilder = _urlBuilder;
    app.factory('UsersService', ['$http', 'MenuService', function ($http, menu) {

        console.log('inside users service');

        var meCache;
        var refreshMeCache = function () {
            meCache = $http.get('/api/v1/users/me');
            menu.refreshItemsCache();
        };   //continues...
这是我的requireJs配置:

define(['angularAMD',
        'angular-route',
        'uiBootstrap',
        'lib/angularSlideables',
        'lib/ng-infinite-scroll',
        'lib/angular-modal-service'], function (angularAMD) {

    console.log('top of routeConfig');

    var app = angular.module('svlPlatform', ['ngRoute', 'ui.bootstrap', 'angularSlideables', 'infinite-scroll', 'angularModalService']).value('THROTTLE_MILLISECONDS', 750);

    app.config(['$routeProvider', function ($routeProvider, $httpProvider) {

        console.log('inside routeConfig');

        //  Because angularAMD is built on requireJS, the following paths to controllerUrl follow requireJs's conventions.
        //  They don't need a .js extention and they are relative to the baseUrl specified in require.config.
        $routeProvider
            .when('/login', angularAMD.route({
                templateUrl: 'views/login.html',
                controllerUrl: 'controllers/login'
            }))
            .when('/me', angularAMD.route({
                templateUrl: 'views/me.html',
                controllerUrl: 'controllers/me'
            }))   //this continues and returns app...
define(['config/routeConfig', 'services/authService', 'services/usersService', 'services/menuService'], function(app) {

    console.log('top of nav controller');

    app.controller('NavController', ['$log', '$anchorScroll', '$location', '$rootScope', 'AuthService', 'UsersService', 'MenuService',
        function ($log, $anchorScroll, $location, $rootScope, auth, users, menu) {

        console.log('inside nav controller');

            var vm = this;
            menuScope = this;

            function loadMenu() {
                menu.items().then(function(response){
                    vm.menuItems = response.data.menuItems;
                    $('body').css("background-color","#f2f2f2");
                    markMenuActive(vm.menuItems);
                }, function(error) {
                    console.log('There was a problem getting the menu data.');
                });
            }   //continues...
require.config({
    baseUrl: 'javascripts',
    paths: {
        'angular': '//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min',
        'angular-route': '//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-route.min',
        'bootstrapJs': '//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min',
        'uiBootstrap': '//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.1/ui-bootstrap-tpls.min',
        'angularAMD': '//cdn.jsdelivr.net/angular.amd/0.2.0/angularAMD.min'
    },
    shim: {
        'angularAMD': ['angular'],
        'bootstrapJs': [],
        'uiBootstrap': ['angular'],
        'lib/angularSlideables': ['angular'],
        'lib/ng-infinite-scroll': ['angular'],
        'angular-route': ['angular'],
        'lib/angular-modal-service': ['angular']
    },
    deps: [
        'bootstrapJs',
        'config/routeConfig',
        'services/authService',
        'services/usersService',
        'services/menuService',
        'controllers/nav',
        'controllers/main',
        'lib/angular-modal-service',
        'config/config',
        'app'
    ]
});
当登录页面(应用程序加载的第一个页面)正确加载时,我在打开控制台后看到:

top of routeConfig
top of users service
top of nav controller
inside routeConfig
inside users service
inside nav controller
但是当页面加载不正确时,我在控制台中看到的就是这个

top of routeConfig
inside routeConfig
top of users service
top of nav controller
…然后是错误


我对引导过程或requireJs的加载过程了解不够,无法弄清楚为什么会发生这种情况以及如何修复它。感谢所有有想法的人。谢谢。

也许这是解决这个问题的最好办法,也许不是。我放弃了在require配置中使用require来指定任何类型的加载顺序,也放弃了使用任何模块定义。我强迫我的几个控制器和服务模块返回应用程序,并让它们串联而不是并联,这迫使我按照指定的顺序运行脚本

因此,我没有让nav.js和usersService.js依赖于routeConfig.js,后者为这两个组件提供应用程序对象,而是让服务依赖于routeConfig.js,而让nav.js模块依赖于usersService(现在返回其应用程序对象)。此方法可以继续包括在引导之前需要加载的其他控制器和服务。最后我调用了另一个文件app.js,它调用angular.bootstrap()(在我的例子中是angularAMD.bootstrap()),现在一切都正常了