您的位置:首页 > Web前端 > AngularJS

AngularJS的启动过程分析

2016-02-20 13:56 711 查看


启动过程


步骤1

用自执行函数的形式让整个代码在加载完成之后立即执行

in
angular.js
Line6
(function(window, document, undefined)


在window上暴露一个唯一的全局对象angular,Line250

/** @name angular */
//如果window.angular已经有值了,就把原有的赋值给前面angular,如果没有则用window.angular空对象赋值给angular
angular = window.angular || (window.angular = {}),
angularModule,
uid = 0;


获得其它工具模块 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的原因)




步骤2

检查是不是多次导入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的三种启动方式


方式1: 自动启动


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></span>
</div>
</body>
</html>


JS
var myModule = angular.module("myModule", []);
myModule.controller('MyCtrl', ['$scope',
function($scope) {
$scope.Name = "Puppet";
}
]);


方式2: 手动启动


在没有ng-app的情况下,只需要在js中添加一段注册代码即可
<body>
<div ng-controller="MyCtrl">
<span></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']);
});


方式3:多个ng-app


ng中,angular的ng-app是无法嵌套使用的,在不嵌套的情况下有多个ng-app,他默认只会启动第一个ng-app,第二个第三个需要手动启动(注意,不要手动启动第一个,虽然可以运行,但会抛异常)
<body>
<div id="app1" ng-app="myModule1">
<div ng-controller="MyCtrl">
<span></span>
</div>
</div>
<div id="app2" ng-app="myModule2">
<div ng-controller="MyCtrl">
<span></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']);
});


步骤3

尝试绑定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></span>
</div>
</div>
</body>

</html>


JS
var myModule = angular.module("myModule", []);
myModule.controller('MyCtrl', ['$scope',
function($scope) {
$scope.Name = "Puppet";
}
]);


查看执行流程




步骤4


发布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



步骤5


初始化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){
....
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: