injector解析

injector 有两种类型 ,ProviderInjector 和InstanceInjector .两者get方法执行起来有差异

ProviderInjector 的结构如下:
`
{
get: function getService(serviceName){
return cacheProvider[serviceName] ;
}
}

`
InstanceInjector 结构如下Pseudocode

{
   get: function getService(serviceName){
        instanceCache[serviceName] ?...

        s = ProviderInjector.get(serviceName)
        invoke(s);
   ...}
}

之所以有这两种injector . providerInjector用来处理module结构里队列中存放的 p结构(第一章提到的),将之处理成Provider构型 ---- 形如 s: {$get:{}} 结构的。
instanceInjector用来实例化Provider构型的。

在service中使用到的$injector,比如 service($injector) $injector就是instanceInjector。

InstanceInjector 会先从ProviderInjector 里拿到同名service再实例化。

ProviderInjector 闭包里有叫cacheProvider的对象,顾名思义会缓存provider。
那么往这个cacheProvider缓存存放Provider构型,则需要$provider.provider。

我们稍作跳跃。

在angular创建injector对象后 ,会利用injector实例化所有模块中的fn.
在所有的模块中‘ng’模块是最先进行处理的。

  • 我们来模拟ng的过程

           +--------------+
           |     |ng|     | <------------+
           +--------------+              |                                       
                     |                   |  require: 'ng-location'
              <hasRequire?>-----Y--------+
              1.
    
    
           +-------------------------+
            |   |_ng-location__|     | 
            |   | ___ ng_______|     |
            |                        | 
           +-------------------------+                                         
                     |                                       
                 <hasRequire?>
                     |  N
                     V 
              2.    
    moduleNgLocation = angular.module('ng-location')               //angularModule(module);
    1.拿到模块  回顾第一章 每一个 module 都有 invokeQueue 和 configBlock 和 runBlocks,
     configBlocks里是这样的结构 ['$inject' ,'invoke' ['s' ,fn(s){}] 
     然后  分别处理该模块的 invokeQueue 和 configBlock       
     runInvokeQueue(moduleFn._invokeQueue);
     runInvokeQueue(moduleFn._configBlocks);
    
     runInvokeQueue的执行过程是  拿其中一条记录['$inject' ,'invoke' ,['$provider' ,fn($provider){}] (第一章提到的p结构)为例
    
         p结构的第一个数据是$inject
         providerInjector.get('$inject');
         前文提到providerInjector.get方法是从从providerCache里取,那么‘$inject’已经存在于providerCache中了吗?
         答案是 Yes  . 在创建好providerInjector和  instanceInjector 中就已经放入providerCache中了
         (providerCache.$inject = providerInjector) .除了$injector ,providerCache中$provider对象也早早的定义了。他们是始祖对象。
    
    
      providerInjector.get('$inject') 的值实际上就是providerInjector自身.
      p结构的第二个数据invoke,
      所以去执行invoke方法 , providerInjector.invoke( ['$provider' ,fn($provider){}])  //p结构的第三个数据
      invoke会先实例化参数’$provider'   会取providerCache中取$provider   ,$provider 随着providerCache定义的时候定义了。
    

    providerCache = {
    $provide: {
    provider: supportObject(provider),
    factory: supportObject(factory),
    service: supportObject(service),
    value: supportObject(value),
    constant: supportObject(constant),
    decorator: decorator
    }
    },
    然后就可以将$provider作为参数 实例化fn
    实例化过程:

      args.unshift(null);
    
      return new (Function.prototype.bind.apply(fn, args))();
    
      实例化好之后就会放入instanceCache中了
          
     至此ng-location模块处理结束 ,ng-location模块中factory都已实例化好,ng-location退出栈。
    回到ng模块,处理方式赘同。
    
           +--------------+
           |     |ng|     | 
           +--------------+                                                  
                     |                
              <hasRequire?>-----Y-------->requireAlreayTackled已处理
                                                             |
                                       new (Function.prototype.bind.apply(ngModule, args))();
    
              3.
    

在ngModule中 provider($compile,$compileProvider) .前文提到$provider.provider方法是往cacheProvider中添加Provider构型的方法。至此能窥探到至关重要的$compile了。

我们回顾下angular的工作过程:
寻找$rootElement ,创建一个injector,这个injector的invoke方法 可以实例化 形如['a',fucntion(a){}]数组的函数。
实际的代码如下
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
function bootstrapApply(scope, element, compile, injector) {
scope.$apply(function() {
element.data('$injector', injector);
compile(element)(scope);
});
}]
);

bootstrapApply会被执行。会调用rootScope.$apply(fn);

$apply(fn), 和 $digest() 是scope中的两个方法 , 该方法会触发 scope上watchers函数.watchers函数正是双向绑定中 data变化反应到ui element中的 机关所在。watch函数是在compilelink阶段绑定到element上的,因为定义指令时element会作为参数传给compilelink函数.
$apply(fn) 实际上是先执行fn再调用$rootScope.$digest();
后面会详细介绍scope.

上面说到 $apply(fn) 实际上是先执行fn;
执行过程
element.data('$injector', injector);
compile(element)(scope);

下章讲解 compile, u element与数据间的因缘在compile展现

posted @ 2016-10-08 17:34  _sihuanhuang  阅读(672)  评论(0)    收藏  举报