injector.jsメモ

AngularJsのinjector.jsを読んだ際のメモ
injectorSpec.js

$provide

$provide: {
    provider: supportObject(provider),
    factory: supportObject(factory),
    service: supportObject(service),
    value: supportObject(value),
    constant: supportObject(constant),
    decorator: decorator
  }

providerからserviceを取得する際は$get属性を使用する。
$get属性の様式

a.$get = function(a,b,c) {};
a.$get = ["a", "b", "c", function(a, b, c) {}];

$getはinstanceInjectorのfactory関数内で利用される。

instanceCache = {},
instanceInjector = (instanceCache.$injector =
  createInternalInjector(instanceCache, function(servicename) {
    var provider = providerInjector.get(servicename + providerSuffix);
    return instanceInjector.invoke(provider.$get, provider, undefined, servicename);
  }, strictDi));

decorator(serviceName, decorFn)

指定したserviceをラップする。
decorFnはfunction($delegate)である。
$delegateはwrapper対象のserviceインスタンス
{$delegate: origInstance}をinvokeのlocalsに渡してDIのときに優先的にfn.apply(self, args)に渡される。

provider(name, provider_)

引数のprovider_はサービスプロバイダークラス

// サービスプロバイダークラスをDIしてインスタンス化  
provider_ = providerInjector.instantiate(provider_);
...
// サービスプロバイダーを登録
return providerCache[name + providerSuffix] = provider_;

service(name, constructor)

constructorはinstantiateでラップされている。

return factory(name, ['$injector', function($injector) {
    return $injector.instantiate(constructor);
}]);

factory(name, factoryFn)

$getを付与

function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }

constant(name, value)

providerCache[name] = value;
instanceCache[name] = value;


anonFn(fn)

anonFn(function(a,b,c) {var a = b + 1;});
// "function(a,b,c)"
anonFn("foo");
// "fn"


annotate(fn, strictDi, name)

var a = angular.injector();
a.annotate(function(aa, bb, _cc_) {});
// ["aa", "bb", "cc"]
a.annotate(["a", "b", "c", function(a,b,c){}]);
// ["a", "b", "c"]
var b = function(){};
b.$inject = ["a", "b", "c"];
a.annotate(b);
// ["a", "b", "c"]


createInternalInjector(cache, factory)

下記でのみ使用されている。

      providerCache = {
        $provide: {
            provider: supportObject(provider),
            factory: supportObject(factory),
            service: supportObject(service),
            value: supportObject(value),
            constant: supportObject(constant),
            decorator: decorator
          }
      },
      providerInjector = (providerCache.$injector =
          createInternalInjector(providerCache, function() {
            throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
          }, strictDi)),
      instanceCache = {},
      instanceInjector = (instanceCache.$injector =
          createInternalInjector(instanceCache, function(servicename) {
            var provider = providerInjector.get(servicename + providerSuffix);
            return instanceInjector.invoke(provider.$get, provider, undefined, servicename);
          }, strictDi));


$injector::getService(serviceName)

$injector::get(getService)である。
createInternalInjector内で実装されている。
serviceNameのserviceインスタンスを返す。
instanceCache[serviceName]が存在している場合、それを返す。
serviceインスタンスを取得する場合は下記のfactory関数から取得したserviceインスタンスを
instanceCacheに格納している。
module.serviceでサービスを登録した場合、constructorはinstantiateでラップされているのでinvokeはサービスインスタンスを返す。

function(servicename) {
    var provider = providerInjector.get(servicename + providerSuffix);
    return instanceInjector.invoke(provider.$get, provider, undefined, servicename);
}

serviceプロバイダーを取得する場合factoryは呼ばれない。
module.service(name, constructor), module.factory(name, factoryFn), module.value(name, value)は実行時に
該当プロバイダーがproviderCacheに格納されている。

return providerCache[name + providerSuffix] = provider_;


$injector::invoke(fn, self, locals, serviceName)

getServiceとinstantiateから呼ばれる。
selfはgetServiceの場合、serviceプロバイダー
selfはinstantiateの場合、空オブジェクト
createInternalInjector内にある。
DIを行う。
selfを主語にしてfnを実行する。そのときにargsにDIするサービスオブジェクトを渡す。
return fn.apply(self, args);
annotateでDIを行うサービスの一覧を取得する。
以下の部分でサービスを取得する。
localsが優先

args.push(
    locals && locals.hasOwnProperty(key)
    ? locals[key]
    : getService(key)
);

fnはannotateに渡すfnと同じ形式で必ずしもfunctionである必要はない。
fn内のfunctionを実行した戻り値を返す。
fnが配列の場合はfnの最後の要素をfnに代入する。
return fn.apply(self, args);

$injector::instantiate(Type, locals, serviceName)

module.serviceでconstructorをラップしている。

return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
}]);

Typeからコンストラクタになる関数を取り出す。
取り出した関数のprototypeを共有した空クラスのinstanceを生成する。
取り出した関数と空クラスのinstanceをinvokeに渡す。
invokeの戻り値がオブジェクトもしくは関数の場合、戻り値を返す。
それ以外の場合はinstanceを返す。

loadModules(modulesToLoad)

loadedModules = new HashMap([], true)
modulesToLoadはarrayである。
各modulesToLoadの要素に対して以下の処理を行う。

runInvokeQueue(moduleFn._invokeQueue);
runInvokeQueue(moduleFn._configBlocks);