AngularJS 的启动过程分析

发布时间:2019-06-04 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了AngularJS 的启动过程分析脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

AngularJS 的启动过程分析

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

启动过程

步骤1

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

    inAngular.js Line6

    (function(window, document, un@R_512_935@d)
    
  • 在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全局对象都有什么东西

    AngularJS 的启动过程分析

  • 接着,我们使用全局对象中的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

    AngularJS 的启动过程分析

  • 我们再来看看injector里都有什么

    /**
     * angular.injector();
     */
    var injector = angular.injector();
    console.log(injector);
    

一共有5个方法
annotate:分析函数签名(不要new的原因)

AngularJS 的启动过程分析

步骤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";
    }
]);

查看执行流程

AngularJS 的启动过程分析

步骤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);

查看控制台

AngularJS 的启动过程分析

构建内置模块 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

总结

  1. 工具函数拷贝到angular全局对象上;
  2. 调用setupModuleLoader方法创建模块定义和加载工具(挂在全局对象window.angular上);
  3. 构建内置模块ng;
  4. 创建ng内置的directive和provider;
  5. 两个重要的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){
....
}

本文原载于@Puppet 原创学习笔记,如需转载请附上 原文链接>>

AngularJS 的启动过程分析

脚本宝典总结

以上是脚本宝典为你收集整理的AngularJS 的启动过程分析全部内容,希望文章能够帮你解决AngularJS 的启动过程分析所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。