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;
-
module.service(name, constructor), module.factory(name, factoryFn), module.value(name, value)、module.provider(name, provider_)はserviceプロバイダーを返す。
-
module.service(name, constructor), module.factory(name, factoryFn), module.value(name, value)はmodule.provider(name, provider_)を内部で利用する際にmodule.provider内でDIする。
-
module.service(name, constructor), module.factory(name, factoryFn), module.value(name, value)はmodule.provider(name, provider_)を内部で利用する際にserviceプロバイダーをproviderCacheに格納する。
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)
- runInvokeQueue(queue)
$provideサービスでserviceプロバイダーオブジェクトをproviderCacheに登録する。
invokeとかもする。
$controllerProviderのregisterを実行する。
loadedModules = new HashMap([], true)
modulesToLoadはarrayである。
各modulesToLoadの要素に対して以下の処理を行う。
- stringの場合
moduleFn = angularModule(module);している。
(angularModule = setupModuleLoader(window);でangularModuleを定義している。
angularModuleはangular.moduleと同じでmodule(name, requires, configFn))
runInvokeQueue(moduleFn._invokeQueue);
runInvokeQueue(moduleFn._configBlocks);
-
functionの場合
-
arrayの場合
-
その他の場合