`
jahu
  • 浏览: 60886 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

angular之注入器与上下文的实现

 
阅读更多
  1. 认真看把
  2.         //这里分三大部分,
            //分别是 provider(providerCache 和 instanceCache 与 providerInjector 和 instanceInjector) 是angualr 最核心的几个组件之一。
    	//loadModules 
            //createInternalInjector	
    	function createInjector(modulesToLoad) {
                    var INSTANTIATING = {},
                            providerSuffix = 'Provider',
                            path = [],
                            loadedModules = new HashMap([], true),
    			//providerCache 基本保存所有组件,这里初始化了$provide组件,在初始化的时候,会加入很多组件
                            providerCache = {
                                    $provide: {
                                            provider: supportObject(provider),
                                            factory: supportObject(factory),
                                            service: supportObject(service),
                                            value: supportObject(value),
                                            constant: supportObject(constant),
                                            decorator: decorator
                                    }
                            },
    			//负责除了decorator组件之外所有组件注入
                            providerInjector = (providerCache.$injector =
                                    createInternalInjector(providerCache, function() {
                                            throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
                                    })),
    			//基本没用,只保存了。constant组件的信息
                            instanceCache = {},
    			//负责decorator组件的注入,得到还是在providerCache 得到
                            instanceInjector = (instanceCache.$injector =
                                    createInternalInjector(instanceCache, function(servicename) {
    					//注意,这里的代码与 getseriver方法的使用,
    					//等于 instanceInjector.getServer还是从providerInjector.get得到
                                            var provider = providerInjector.get(servicename + providerSuffix);
                                            return instanceInjector.invoke(provider.$get, provider);
                                    }));
    
    
                    forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
    
                    return instanceInjector;
    
                    ////////////////////////////////////
                    // $provider 组件包括factory,provider,service,value,constant,decorator,从这里就可以看到这些组件的不同之处。
                    ////////////////////////////////////
    
                    function supportObject(delegate) {
                            return function(key, value) {
                                    if (isObject(key)) {
                                            forEach(key, reverseParams(delegate));
                                    } else {
                                            return delegate(key, value);
                                    }
                            };
                    }
    
                    function provider(name, provider_) {
                            assertNotHasOwnProperty(name, 'service');
                            if (isFunction(provider_) || isArray(provider_)) {
                                    provider_ = providerInjector.instantiate(provider_);
                            }
                            if (!provider_.$get) {
                                    throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
                            }
                            return providerCache[name + providerSuffix] = provider_;
                    }
    
                    function factory(name, factoryFn) {
                            return provider(name, { $get: factoryFn });
                    }
    
                    function service(name, constructor) {
                            return factory(name, ['$injector', function($injector) {
                                    return $injector.instantiate(constructor);
                            }]);
                    }
    
                    function value(name, val) {
                            return factory(name, valueFn(val));
                    }
    
                    function constant(name, value) {
                            assertNotHasOwnProperty(name, 'constant');
                            providerCache[name] = value;
                            instanceCache[name] = value;
                    }
    
                    function decorator(serviceName, decorFn) {
                            var origProvider = providerInjector.get(serviceName + providerSuffix),
                                    orig$get = origProvider.$get;
    
                            origProvider.$get = function() {
                                    var origInstance = instanceInjector.invoke(orig$get, origProvider);
                                    return instanceInjector.invoke(decorFn, null, { $delegate: origInstance });
                            };
                    }
    
                    ////////////////////////////////////
                    // Module Loading
                    ////////////////////////////////////
                    function loadModules(modulesToLoad) {
                            var runBlocks = [],
                                    moduleFn, invokeQueue, i, ii;
                            forEach(modulesToLoad, function(module) {
                                    if (loadedModules.get(module)) return;//如何依赖的组件已经初始化过,就不初始化了。
                                    loadedModules.put(module, true);//加入缓存
    
                                    try { 
                                            if (isString(module)) {
                                                    moduleFn = angularModule(module);//通过module名得到module的相关数据,等于angular.module(“”)
                                                    //loadModules(moduleFn.requires) 先加载依赖,同是把依赖的 run 方法 加入到runBlocks 中。
    						runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
    						//循环执行 module中的基础方法 ,在初始化,会加载很多provider,
                                                    for (invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
                                                            var invokeArgs = invokeQueue[i],
                                                                    provider = providerInjector.get(invokeArgs[0]);
    
                                                            provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
                                                    }
                                            } else if (isFunction(module)) {
                                                    runBlocks.push(providerInjector.invoke(module));
                                            } else if (isArray(module)) {
                                                    runBlocks.push(providerInjector.invoke(module));
                                            } else {
                                                    assertArgFn(module, 'module');
                                            }
                                    } catch (e) {
                                            if (isArray(module)) {
                                                    module = module[module.length - 1];
                                            }
                                            if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
                                                    // Safari & FF's stack traces don't contain error.message content
                                                    // unlike those of Chrome and IE
                                                    // So if stack doesn't contain message, we create a new string that contains both.
                                                    // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
                                                    /* jshint -W022 */
                                                    e = e.message + '\n' + e.stack;
                                            }
                                            throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
                                                    module, e.stack || e.message || e);
                                    }
                            });
                            return runBlocks;
                    }
    
                    ////////////////////////////////////
                    // internal Injector  注入器的实现 ,,缓存对象,与执行工厂,会实例化两个依赖注入对象,可以说白了,基本就等于一个。
                    ////////////////////////////////////
    
                    function createInternalInjector(cache, factory) {
    
                            function getService(serviceName) {
                                    if (cache.hasOwnProperty(serviceName)) {
                                            if (cache[serviceName] === INSTANTIATING) {
                                                    throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
                                                            serviceName + ' <- ' + path.join(' <- '));
                                            }
                                            return cache[serviceName];
                                    } else {
                                            try {
                                                    path.unshift(serviceName);
                                                    cache[serviceName] = INSTANTIATING;
                                                    return cache[serviceName] = factory(serviceName);
                                            } catch (err) {
                                                    if (cache[serviceName] === INSTANTIATING) {
                                                            delete cache[serviceName];
                                                    }
                                                    throw err;
                                            } finally {
                                                    path.shift();
                                            }
                                    }
                            }
    			//fn 执行的方法,locals方法需要的实参,self方法执行的上下文,也就是对象,也就是调用方法的this参数
    	
                            function invoke(fn, self, locals) {
                                    var args = [],
                                            $inject = annotate(fn),
                                            length, i,
                                            key;
    
                                    for (i = 0, length = $inject.length; i < length; i++) {
                                            key = $inject[i];
                                            if (typeof key !== 'string') {
                                                    throw $injectorMinErr('itkn',
                                                            'Incorrect injection token! Expected service name as string, got {0}', key);
                                            }
                                            //注意这里,如果参数在locals里面没有,就在 service里面得到。为什么有locals
                                            // 比如 作用域不是服务,节点与属性也不是服务,只能从locals得到。
                                            args.push(
                                                    locals && locals.hasOwnProperty(key) ? locals[key] : getService(key)
                                            );
                                    }
                                    if (isArray(fn)) {
                                            fn = fn[length];//注意这里,fn如果是数组那么最后一个才是执行的方法
                                    }
    
                                    // http://jsperf.com/angularjs-invoke-apply-vs-switch
                                    // #5388
                                    return fn.apply(self, args);
                            }
    			//这个方法 使用与invoke的区别就是使用了原型链而已,javascript这个语言就是麻烦。
                            function instantiate(Type, locals) {
                                    var Constructor = function() {},
                                            instance, returnedValue;
    
                                    // Check if Type is annotated and use just the given function at n-1 as parameter
                                    // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
                                    Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
                                    instance = new Constructor();
                                    returnedValue = invoke(Type, instance, locals);//注意这里调用了  invoke 方法
    
                                    return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
                            }
    
                            return {
                                    invoke: invoke,
                                    instantiate: instantiate,
                                    get: getService,
                                    annotate: annotate,
                                    has: function(name) {
                                            return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
                                    }
                            };
                    }
            }
    
     
分享到:
评论

相关推荐

    angular6 中文官方文档

    Angular 的基本构造块是 NgModule,它为组件提供了编译的上下文环境。 NgModule 会把相关的代码收集 到一些功能集中。Angular 应用就是由一组 NgModule 定义出的。 应用至少会有一个用于引导应用的根模 块,通常还会...

    Angular Source Code Tour [pdf]

    **Zone.js** 是 Angular 中的一个关键库,它主要用于处理异步操作和上下文切换。通过拦截 JavaScript 的异步 API(如 `setTimeout` 和 `Promise`),Zone.js 能够为这些操作添加额外的行为。这对于 Angular 来说非常...

    angular示例

    AngularJS,通常简称为Angular,是一款强大的前端JavaScript框架...每个文件都提供了实际应用的上下文,是学习和实践Angular技能的好资源。在实践中,结合这些示例,开发者能够构建出功能丰富的、响应式的Web应用程序。

    ng-book The Complete Guide to Angular 5

    以上知识点涵盖了Angular 5框架的核心概念,以及与之相关的开发工具和流程。对于有志于深入学习Angular的开发者来说,这些信息是基础且十分关键的,它们能帮助开发者构建高质量的Web应用,并在项目中有效运用Angular...

    angular.js-master

    - **ng-app**:在HTML中通过`ng-app`指令声明AngularJS应用的开始,它定义了一个应用的上下文。 - **模块依赖注入**:AngularJS的模块系统允许我们定义服务、配置、指令等,并可以通过模块间的依赖关系来组织代码。...

    angular book 4

    3. 代码块和上下文:代码块是展示代码片段的部分,每段代码都有详细的注释和上下文介绍,以便读者可以准确理解代码的功能和应用场合。 4. 代码块编号:代码块通常会有编号,方便在文本中引用和讨论特定的代码部分。...

    ng-book. 2.Angular

    4. 书籍结构:书中可能包括了前言、如何阅读本书、Angular CLI指南、代码示例的运行、代码块和上下文、代码块编号、技术支援响应时间、版本管理说明、获取帮助、联系方法、章节概述等部分。 5. 项目开发:文档中...

    angular学习笔记

    此外,你可以使用`$injector`服务来动态注入服务,或者在控制器定义中使用`@Context`注解注入如Request、Response等上下文对象。 过滤器是Angular中用于格式化数据的工具,如`| filterName`,它可以用于日期格式化...

    angular-audio-context:Web Audio API的AudioContext的Angular包装器

    角度音频上下文Web Audio API的AudioContext的Angular包装器。 除了作为包装器之外,该模块还修补了不存在的AudioContext和带前缀的AudioContext版本。 它使用来执行此操作。用法可以通过安装此模块,如下所示: npm...

    angular权威教程2222

    接着是作用域(Scope)的概念,它是一个执行上下文,用于保存模型数据,同时负责处理视图与控制器之间的数据绑定。 控制器(Controller)作为视图与模型之间的桥梁,负责接收用户输入并返回输出。本书还对表达式...

    Angular JS权威教程

    - **作用域(Scope)**: 控制着数据模型的上下文环境,负责在模型和视图之间传递数据。作用域对象是由Angular自动创建的,用于保存应用的状态信息。 - **控制器(Controller)**: 负责处理逻辑和业务操作,与视图层分离...

    demoangular

    后端可能包含对数据库操作的模型、控制器和数据库上下文,确保数据安全和有效。 总的来说,"demoangular"项目是一个很好的学习资源,涵盖了现代Web开发中的两个重要技术栈的集成。通过分析和实践这个项目,开发者...

    Angular-WebApi

    4. `Data` 目录:可能包含数据库连接配置和数据库上下文类,用于与数据库进行交互。 5. `Startup.cs` 文件:WebAPI的启动配置文件,定义路由和其他设置。 6. `package.json` 和 `npm-shrinkwrap.json`:Angular项目...

    Angular实现的简单定时器功能示例

    `$timeout`与`setTimeout`类似,但会自动在AngularJS的上下文中执行回调函数,因此不需要手动调用`$scope.$apply`。在示例中,它只执行一次,与`$interval`不同。 ```javascript $timeout(function () { $scope...

    angular-es6-skeleton-源码.rar

    - **箭头函数(Arrow Functions)**:简洁的语法,保持正确的`this`上下文。 - **模板字符串(Template Strings)**:方便地插入变量和表达式到字符串中。 - **导入/导出(Imports/Exports)**:模块化代码,使得...

    angular-noty:Noty的包装器-酷似咆哮的通知

    简单的Noty包装器库,将Noty带入Angular上下文。 可凉亭式安装。 ##启动开发模式要运行演示,您需要安装gulp并将所有npm和bower deps安装到项目中。 npm install gulp -gnpm installbower installgulp ##如何在项目...

    SB Angular Inspector-crx插件

    选择一个元素将启用一个新面板“ SB Angular”,该面板显示当前选定的元素:-组件-指令-侦听器-上下文-注入器如果它们适用于当前元素。 SB Angular Inspector还允许您修改“ SB Angular”面板中的值,然后使用此扩展...

Global site tag (gtag.js) - Google Analytics