@yiranphp
2016-04-06T02:28:20.000000Z
字数 5289
阅读 4031
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){}]形式,则取数组中最后一项作为执行函数fnif (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);}};}}