然后,我们看看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} } }