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  阅读(686)  评论(0)    收藏  举报