然后,我们看看AngularJS关于provider、constant等实现。
var providerSuffix="Provider";//这个参数,在providerCache写属性名时使用,用以区分constant以及普通的provider注入
function provider(name, provider_) {
assertNotHasOwnProperty(name, 'service');//保证name !== 'hasOwnProperty'
if (isFunction(provider_) || isArray(provider_)) {
provider_ = providerInjector.instantiate(provider_);//将传入的provider进行注入。providerInjector //以后讲解
}
if (!provider_.$get) {//每一个provider 都必须有$get属性。。
throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
}
return providerCache[name + providerSuffix] = provider_;
}
function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
function valueFn(value) {return function() {return value;};}
function value(name, val) { return factory(name, valueFn(val)); }
function constant(name, value) {
assertNotHasOwnProperty(name, 'constant');//name must not eqauls "hasOwnProperty"
providerCache[name] = value;
instanceCache[name] = value;
//这样做之后,可以$provider,$service 中都访问
}
下面为createInternalInjector,ProviderInjector由createInternalInjector实现。
var INSTANTIATING = {};//避免循环引用自己
var path=[];//由来做错误提示的。
function createInternalInjector(cache, factory) {
function getService(serviceName) {
if (cache.hasOwnProperty(serviceName)) {
if (cache[serviceName] === INSTANTIATING) {
throw $injectorMinErr('cdep', 'Circular dependency found: {0}', path.join(' <- '));
}
return cache[serviceName];
} else {
try {//当根据服务名称搜索不到时,
//先让cache[serviceName]=INSTANTIATING,factory函数会返回值或抛异常
//而factory在返回值时,可能还会在调用同一个module下的createInternalInjector里的getService方法
//这时,path的记录就可用来写注入异常路径提示,而INSTANTIATING则可以进行检验是否是循环引用了
path.unshift(serviceName);
cache[serviceName] = INSTANTIATING;
return cache[serviceName] = factory(serviceName);
} finally {
path.shift();//用来清空路径信息
}
}
}
function invoke(fn, self, locals){
var args = [],
$inject = annotate(fn),//获取需要注入的引用名称数组
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);
}
args.push(
locals && locals.hasOwnProperty(key)//如果当前module没有,则取找cache缓存(注入的其它module)中
? locals[key]
: getService(key)
);
}
if (!fn.$inject) {
// this means that we must be an array.
//fn经过annotate处理后,如果没有$inject属性,则证明,fn为['a','b',function(a,b){}] 的形式。
fn = fn[length];
}
// http://jsperf.com/angularjs-invoke-apply-vs-switch
// #5388
return fn.apply(self, args);
}
function instantiate(Type, locals) {//将传入的Type的原型注入到新实例化的函数或者object原型上去。
var Constructor = function() {},
instance, returnedValue;
// Check if Type is annotated and use just the given function at n-1 as parameter
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
instance = new Constructor();//生成一个全新的函数实例用以加载需要注入的function
returnedValue = invoke(Type, instance, locals);
return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
}
return {
invoke: invoke,
instantiate: instantiate,
get: getService,
annotate: annotate,//暴露出annotate 函数。
has: function(name) {
return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
}
};
}
}
简洁点记忆就是:
createInternalInjector返回一个object。
createInternalInjector(cache,factory){
return
{
/*
*fn.apply(self,args) args来源于locals[key]
*和get[key],key值为fn的注入参数。
*/
invoke: function(fn, self, locals){...}
/*
*先根据cache,cache[serviceName],如果undefined,
*则factory(serviceName)获取
*/
get:function(serviceName){...}
/*
*生成一个不带参数的instance=function(){},并且intance获得Type的prototype,
*调用returnvalue=invoke(Type, instance, locals),如果returnvalue不是object或者
*function,返回instance,否则返回returnvalue
*/
instantiate:function(Type, locals){...}
annotate:function(fn){//获取要注入的参数名称}
has:function(name){//检测providerCach和cache有没有name atrribute}
}
}