@yiranphp
2016-04-06T10:28:20.000000Z
字数 5289
阅读 3651
angular
依赖注入:在调用bootstrap的时候,会调用createInjector来创建一个注射器进行注入。
function createInjector(modulesToLoad, strictDi) {
// 依赖注入的模式:严格或者宽松
strictDi = (strictDi === true);
var INSTANTIATING = {},
providerSuffix = 'Provider',
path = [],
// 哈希表,与对象字面量作为哈希表不同,它不仅支持字符串作为键值,还支持对象作为键值
loadedModules = new HashMap([], true),
providerCache = {
// ... ...
},
providerInjector = (providerCache.$injector =
createInternalInjector(providerCache, function(serviceName, caller) {
// ... ...
})),
instanceCache = {},
instanceInjector = (instanceCache.$injector =
createInternalInjector(instanceCache, function(serviceName, caller) {
// ... ...
}));
forEach(loadModules(modulesToLoad), function(fn) {
if (fn) instanceInjector.invoke(fn);
});
return instanceInjector;
function supportObject(delegate) {}
function provider(name, provider_) {}
function enforceReturnValue(name, factory) {}
function factory(name, factoryFn, enforce) {}
function service(name, constructor) {}
function value(name, val) {}
function constant(name, value) {}
function decorator(serviceName, decorFn) {}
function loadModules(modulesToLoad) {}
function createInternalInjector(cache, factory) {
function getService(serviceName, caller) {}
function invoke(fn, self, locals, serviceName) {}
function instantiate(Type, locals, serviceName) {}
return {
// ... ...
};
}
}
createInjector的主体代码如下:
strictDi = (strictDi === true);
var INSTANTIATING = {},
providerSuffix = 'Provider',
path = [],
loadedModules = new HashMap([], true),
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(serviceName, caller) {
if (angular.isString(caller)) {
path.push(caller);
}
throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
})),
instanceCache = {},
instanceInjector = (instanceCache.$injector =
createInternalInjector(instanceCache, function(serviceName, caller) {
var provider = providerInjector.get(serviceName + providerSuffix, caller);
return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
}));
forEach(loadModules(modulesToLoad), function(fn) {
if (fn) instanceInjector.invoke(fn);
});
return instanceInjector;
可以看到,主要是一些变量的定义,然后在forEach中执行loadModules依次加载模块,最后返回instanceInjector。
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var $injectorMinErr = minErr('$injector');
function anonFn(fn) {
// For anonymous functions, showing at the very least the function signature can help in
// debugging.
var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
args = fnText.match(FN_ARGS);
if (args) {
return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
}
return 'fn';
}
function annotate(fn, strictDi, name) {
var $inject,
fnText,
argDecl,
last;
if (typeof fn === 'function') {
if (!($inject = fn.$inject)) {
$inject = [];
if (fn.length) {
if (strictDi) {
if (!isString(name) || !name) {
name = fn.name || anonFn(fn);
}
throw $injectorMinErr('strictdi',
'{0} is not using explicit annotation and cannot be invoked in strict mode', name);
}
fnText = fn.toString().replace(STRIP_COMMENTS, '');
argDecl = fnText.match(FN_ARGS);
forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
arg.replace(FN_ARG, function(all, underscore, name) {
$inject.push(name);
});
});
}
fn.$inject = $inject;
}
} else if (isArray(fn)) {
last = fn.length - 1;
assertArgFn(fn[last], 'fn');
$inject = fn.slice(0, last);
} else {
assertArgFn(fn, 'fn', true);
}
return $inject;
}
总结一下annotate:
1. 如果fn是一个函数,如果定义了fn.$inject属性,直接返回;如果未定义,则通过toString()得到其字符串形式,然后取出其中参数放在数组$inject中,这里涉及到依赖注入的严格模式
2. 如果fn是一个数组,即['service',function(service){}]形式,则将该数组的最后一项剔除,其余部分放在inject数组就是函数的真正依赖
function createInternalInjector(cache, factory) {
// 获取依赖的实例:如果在注册列表中存在,就返回,没有的话,调用工厂生成实例
function getService(serviceName, caller) {
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, caller);
} catch (err) {
if (cache[serviceName] === INSTANTIATING) {
delete cache[serviceName];
}
throw err;
} finally {
path.shift();
}
}
}
// 依赖注入的完成者
function invoke(fn, self, locals, serviceName) {
if (typeof locals === 'string') {
serviceName = locals;
locals = null;
}
var args = [],
// 通过annotate方法得到需要注入的参数;
$inject = createInjector.$$annotate(fn, strictDi, serviceName),
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或getService依次得到需要注入的参数的实例,放在args数组中;
args.push(
locals && locals.hasOwnProperty(key)
? locals[key]
: getService(key, serviceName)
);
}
// 如果fn是一个数组,即['service',function(service){}]形式,则取数组中最后一项作为执行函数fn
if (isArray(fn)) {
fn = fn[length];
}
return fn.apply(self, args);
}
// 实例化服务
function instantiate(Type, locals, serviceName) {
var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
var returnedValue = invoke(Type, instance, locals, serviceName);
return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
}
return {
invoke: invoke,
instantiate: instantiate,
get: getService,
annotate: createInjector.$$annotate,
has: function(name) {
return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
}
};
}
}