Angularjs的启动过程分析
本文介绍了angularjs的启动过程分析,分享给大家
启动过程(v1.3.9)
步骤一
用自执行函数的形式让整个代码在加载完成之后立即执行
in angular.js
line6
(function(window, document, undefined)
在window上暴露一个唯一的全局对象angular,line250
angular = window.angular || (window.angular = {})
获得其它工具模块 line 2129
function publishexternalapi(angular) { extend(angular, { 'bootstrap': bootstrap, 'copy': copy, 'extend': extend, 'equals': equals, 'element': jqlite, 'foreach': foreach, 'injector': createinjector, 'noop': noop, 'bind': bind, .....
我们来看看angular全局对象都有什么东西
接着,我们使用全局对象中的isfunction 来遍历一下angular全局对象上的属性,函数
var counter = 0; for (var p in angular) { counter++; if (angular.isfunction(angular[p])) { console.log("function->" + p); } else { console.log("property-->" + p + "-->" + angular[p]); } } console.log(counter);
有两个property,其它都是function
我们再来看看injector里都有什么
/** * angular.injector(); */ var injector = angular.injector(); console.log(injector);
一共有5个方法
annotate:分析函数签名(不要new的原因)
步骤二
检查是不是多次导入angular:window.angular.bootstrap(通过检查指定的元素上是否已经存在injector进行判断)
in angular.js
line 26041
if (window.angular.bootstrap) { //angularjs is already loaded, so we can return here... console.log('warning: tried to load angular more than once.'); return; }
angular的三种启动方式
自动启动
angular会自动的找到ng-app,将它作为启动点,自动启动
<!doctype html> <html ng-app="mymodule"> <head> <title>new page</title> <meta charset="utf-8" /> <script type="text/javascript" src="../../vendor/bower_components/angular/angular.min.js"></script> <script type="text/javascript" src="./02.boot1.js"></script> </head> <body> <div ng-controller="myctrl"> <span>{{name}}</span> </div> </body> </html>
js
var mymodule = angular.module("mymodule", []); mymodule.controller('myctrl', ['$scope', function($scope) { $scope.name = "puppet"; } ]);
手动启动
在没有ng-app的情况下,只需要在js中添加一段注册代码即可
<body> <div ng-controller="myctrl"> <span>{{name}}</span> </div> </body>
js
var mymodule = angular.module("mymodule", []); mymodule.controller('myctrl', ['$scope', function($scope) { $scope.name = "puppet"; } ]); /** * 这里要用ready函数等待文档初始化完成 */ angular.element(document).ready(function() { angular.bootstrap(document, ['mymodule']); });
多个ng-app
ng中,angular的ng-app是无法嵌套使用的,在不嵌套的情况下有多个ng-app,他默认只会启动第一个ng-app,第二个第三个需要手动启动(注意,不要手动启动第一个,虽然可以运行,但会抛异常)
<body> <div id="app1" ng-app="mymodule1"> <div ng-controller="myctrl"> <span>{{name}}</span> </div> </div> <div id="app2" ng-app="mymodule2"> <div ng-controller="myctrl"> <span>{{name}}</span> </div> </div> </body>
js
/** * 第一个app * @type {[type]} */ var mymodule1 = angular.module("mymodule1", []); mymodule1.controller('myctrl', ['$scope', function($scope) { $scope.name = "puppet"; } ]); // angular.element(document).ready(function() { // angular.bootstrap(app1, ['mymodule1']); // }); /** * 第二个app * @type {[type]} */ var mymodule2 = angular.module("mymodule2", []); mymodule2.controller('myctrl', ['$scope', function($scope) { $scope.name = "vincent"; } ]); angular.element(document).ready(function() { angular.bootstrap(app2, ['mymodule2']); });
步骤三
尝试绑定jquery,如果发现导入了jquery ,则使用导入的jquery,否则,使用angular自己封装的jqlite
in angular.js
line 1521:
bindjquery();
in angular.js
line 1534:
jquery = window.jquery; if (jquery && jquery.fn.on) { jqlite = jquery; extend(jquery.fn, { scope: jqliteprototype.scope, isolatescope: jqliteprototype.isolatescope, controller: jqliteprototype.controller, injector: jqliteprototype.injector, inheriteddata: jqliteprototype.inheriteddata });
测试
<html ng-app="mymodule"> <body> <div> <div ng-controller="myctrl"> <span>{{name}}</span> </div> </div> </body> </html>
js
var mymodule = angular.module("mymodule", []); mymodule.controller('myctrl', ['$scope', function($scope) { $scope.name = "puppet"; } ]);
查看执行流程
步骤四
发布ng提供的api
in angular.js
line 2162 : publishexternalapi(angular);
//构建模块加载器 angularmodule = setupmoduleloader(window); try { angularmodule('nglocale'); } catch (e) { angularmodule('nglocale', []).provider('$locale', $localeprovider); }
模块加载器的实现原理
in angular.js
function setupmoduleloader(window)
function setupmoduleloader(window) { var $injectorminerr = minerr('$injector'); var ngminerr = minerr('ng'); function ensure(obj, name, factory){ return obj[name] || (obj[name] = factory()); } var angular = ensure(window, 'angular', object); // we need to expose `angular.$$minerr` to modules such as `ngresource` that reference it during bootstrap angular.$$minerr= angular.$ $minerr || minerr; //把module方法放到angular的全局对象上,ensure就是一个属性拷贝的过程 return ensure(angular, 'module', function(){ //模块缓存 var modules = {}; }
把工具函数给载到模块里
return function module(name, requires, configfn) { ...... }
查看模块里所包含的内容
<!doctype html> <html ng-app="mymodule"> </html>
js
/** * 定义模块 */ var mymodule = angular.module("mymodule", []); /** * 从debug的过程可以看到,angular中的“模块”只是一个闭包空间(或者叫命名空间) * 所有模块都被注册在modules这个对象上 */ console.log(mymodule);
查看控制台
构建内置模块ng
in angular.js
line 2169 publishexternalapi(angular)
angularmodule('ng', ['nglocale'], ['$provide', function ngmodule($provide) { // $ $sanitizeuriprovider needs to be before $compileprovider as it is used by it. $provide.provider({ $ $sanitizeuri: $$sanitizeuriprovider }); $provide.provider('$compile', $compileprovider). directive({ a: htmlanchordirective, input: inputdirective, ......
加载了所有内置的directive,provider.注册ng内核provider:两个最重要的$parser
和 $rootscope
总结
- 工具函数拷贝到angular全局对象上;
- 调用setupmoduleloader方法创建模块定义和加载工具(挂在全局对象window.angular上);
- 构建内置模块ng;
- 创建ng内置的directive和provider;
- 两个重要的provider:$parse 和 $rootscope;
步骤五
初始化angular - 查找ng-app
jqlite(document).ready(function() { angularinit(document, bootstrap); });
bootstrap
创建injector,拉起内核和启动模块,调用compile服务(一个ng-app只有一个injector)
in angular.js
line 1415
function bootstrap(element, modules, config){ .... }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。