AngularJS的启动过程分析

本文例子所使用版本为 v1.3.9

启动过程

步骤1

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

(function(window, document, undefined)

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

    /** @name angular */    //如果window.angular已经有值了,就把原有的赋值给前面angular,如果没有则用window.angular空对象赋值给angularangular = 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>{{Name}}</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>{{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']);});
方式3:多个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']);});

步骤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>{{Name}}</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){....}

 

 

相关文章