当构建大型网站或应用程序在AngularJS许多/观点的路线,它将不会加载所有的文件,如控制器、指令等是很好的,在第一次加载。理想情况下,在第一次加载,只有文物所需要的路线的问题,将加载。这可能是在一个下载或多取决于应用程序,但是,它只会是什么需要渲染特定的路由。当用户导航App改变路线,其他文物尚未加载,将被加载时需要有。这种潜力不仅应该加快初始页面的负载,而且还应该导致带宽不被浪费。这个帖子,我的目的是展示的文物如控制器和指令可以实现与AngularJS的懒加载。
为了延迟加载的文物如AngularJS控制器和指示,有两个主要问题,必须回答如下:
1、如何在应用启动后,对一个模块进行懒加载的注册
2、在应用程序中,如何选择脚本加载的实际位置
第一个问题的结果从当前无法注册文物后,应用程序引导,使用模块API。换句话说,如果你想与一个已经自举程序登记一个新的控制器,使用下面的代码:
angular.module('app').controller('SomeLazyController', function($scope)
{
$scope.key = '...';
});
you would get the following error when you reference the controller with the ng-controller directive:
Error: Argument ‘SomeLazyController’ is not a function, got undefined
目前,唯一的方法(我知道)登记的文物已经引导应用程序,不使用模块的API,但使用有关的AngularJS提供者代替。
供应商基本上是被用来创建和配置的AngularJS文物实例对象。因此,为了登记一个懒惰的控制器,你可以使用
controllerprovider。同样的,要登记一个指令,你会用
compileprovider美元,登记过滤器可以使用$filterprovider,并登记等服务,你会使用提供服务。代码将看起来像这样的控制器和指令:
// Registering a controller after app bootstrap
$controllerProvider.register('SomeLazyController', function($scope)
{
$scope.key = '...';
});
// Registering a directive after app bootstrap
$compileProvider.directive('SomeLazyDirective', function()
{
return {
restrict: 'A',
templateUrl: 'templates/some-lazy-directive.html'
}
})
// etc
现在与供应商的事情是,他们只有在模块配置。因此,一个参考他们将不得不保持,以便他们可以用来以后登记懒惰文物。作为一个例子,为了获得相关的供应商,您可以设置您的应用程序模块类似以下:
appModule.js:
(function()
{
var app = angular.module('app', []);
app.config(function($routeProvider, $controllerProvider, $compileProvider, $filterProvider, $provide)
{
app.controllerProvider = $controllerProvider;
app.compileProvider = $compileProvider;
app.routeProvider = $routeProvider;
app.filterProvider = $filterProvider;
app.provide = $provide;
// Register routes with the $routeProvider
});
})();
You would then be able to define a lazy controller as follows:
angular.module('app').controllerProvider.resgister('SomeLazyController', function($scope)
{
$scope.key = '...';
});
仍然存在的问题,但是,在那里加载的懒惰文物,如上述控制器,将发生使用您的脚本加载器的选择。目前,只有一个地方,这可以发生“干净”,它是在“解决”属性的路由定义。
当定义一个路由使用routeprovider美元,你可以指定一个可选的关键/工厂地图的依赖,应注入路由控制器。使用“解决”属性指定此依赖关系图如下:
$routeProvider.when('/about', {templateUrl:'views/about.html', controller:'AboutViewController' resolve:{key:factory}
依赖映射中的“键”将是依赖项的名称,而“工厂”将是一个字符串,该字符串是作为依赖项的现有服务的别名,或作为其依赖项的返回值的可注入函数。现在,如果函数返回一个承诺,承诺将得到解决之前的路线是“渲染”(可以这么说)。因此,必须检索异步的依赖,如延迟加载的文物,可以使用一个依赖图的函数返回的承诺,将一次解决懒惰的文物已被加载的检索。这确保了所有的懒惰文物加载之前的路线呈现。一个路由定义中指定要使用的懒惰依赖美元script.js脚本加载器加载的一个例子,如下:
$routeProvider.when('/about', {templateUrl:'views/about.html', resolve:{deps:function($q, $rootScope)
{
var deferred = $q.defer();
var dependencies =
[
'controllers/AboutViewController.js',
'directives/some-directive.js'
];
// Load the dependencies
$script(dependencies, function()
{
// all dependencies have now been loaded by so resolve the promise
$rootScope.$apply(function()
{
deferred.resolve();
});
});
return deferred.promise;
}}});
有一件事,也应该指出的是,由于承诺的决议将最有可能的AngularJS的上下文之外发生的,如在上面的例子中,它在scriptjs美元背景下发生的,AngularJS已经被明确告知当诺言已经解决(这么说)。这是通过承诺内的应用方法$rootscopeas在实现:
$rootScope.$apply(function()
{
deferred.resolve();
});
如果承诺不解决在应用$rootscope,将不会对初始页面加载渲染。
现在所有这些应用程序模块定义,将产生以下:
appModule.js:
(function()
{
var app = angular.module('app', []);
app.config(function($routeProvider, $controllerProvider, $compileProvider, $filterProvider, $provide)
{
app.controllerProvider = $controllerProvider;
app.compileProvider = $compileProvider;
app.routeProvider = $routeProvider;
app.filterProvider = $filterProvider;
app.provide = $provide;
// Register routes with the $routeProvider
$routeProvider.when('/', {templateUrl:'views/home.html'});
$routeProvider.when('/about', {templateUrl:'views/about.html', resolve:{deps:function($q, $rootScope)
{
var deferred = $q.defer();
var dependencies =
[
'controllers/AboutViewController.js',
'directives/some-directive.js'
];
$script(dependencies, function()
{
// all dependencies have now been loaded by $script.js so resolve the promise
$rootScope.$apply(function()
{
deferred.resolve();
});
});
return deferred.promise;
}}});
});
})();
Finally you can bootstrap the app using code similar to the following if using $script.js:
$script(['appModule.js'], function()
{
angular.bootstrap(document, ['app'])
});
这些都或多或少地要在AngularJS实现懒加载的步骤。总之,您将首先定义应用程序模块以保持相关提供商的实例。然后,您将定义您的懒惰的文物登记自己使用的供应商,而不是模块的API。然后使用一个“解析”函数返回你的路由定义中的一个承诺,你将加载所有的懒惰的文物和解决的承诺,一旦他们已经加载。这将确保所有的懒惰文物将提供相关的路线之前呈现。另外,别忘了解决承诺内rootscope美元。美元的申请,如果该决议将在AngularJS发生的事情。然后,您将创建一个“引导”的剧本,第一次加载的应用程序模块,在引导程序。最后,你会链接到你的索引HTML文件的启动脚本。
看到一个Runnable实例使用异步模块定义与RequireJS,在示例应用程序一看。请注意,但是,示例应用程序只是一个非常基本的(即,不生产质量)的例子。
以上都是废话,直接看代码:
html:
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<script src="main/js/angular.min.js"></script>
<script src="main/js/angular-route.min.js"></script>
<script src="main/js/script.min.js"></script>
<script src="main/js/app.js"></script>
</head>
<body>
<a href="#/about" title="">about</a>
<a href="#/home" title="">home</a>
<a href="#/alterplaplan" title="">alterplaplan</a>
<div ng-view></div>
</body>
</html>
js:
var app = angular.module('app', ["ngRoute"]);
app.config(["$routeProvider", "$controllerProvider", "$compileProvider", "$filterProvider", "$provide",function($routeProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
app.controllerProvider = $controllerProvider;
app.compileProvider = $compileProvider;
app.routeProvider = $routeProvider;
app.filterProvider = $filterProvider;
app.provide = $provide;
// Register routes with the $routeProvider
$routeProvider.when('/home', {
templateUrl: 'ClassReallot/html/home.html'
});
$routeProvider.when('/about', {
templateUrl: 'main/html/about.html',
resolve: {
deps: function($q, $rootScope) {
var deferred = $q.defer();
var dependencies =
[
'ClassReallot/js/courseController.js'
];
$script(dependencies, function() {
$rootScope.$apply(function() {
deferred.resolve(dependencies);
});
});
return deferred.promise;
}
}
});
$routeProvider.when('/alterplaplan', {
templateUrl: 'ClassReallot/html/alterplaplan.html',
resolve: {
deps: function($q, $rootScope) {
var deferred = $q.defer();
var dependencies =
[
'ClassReallot/js/courseController.js'
];
$script(dependencies, function() {
$rootScope.$apply(function() {
deferred.resolve(dependencies);
});
});
return deferred.promise;
}
}
});
}]);