[关闭]
@yiranphp 2016-04-06T10:28:20.000000Z 字数 5289 阅读 3651

angularJs 依赖注入

angular


1、createInjector

依赖注入:在调用bootstrap的时候,会调用createInjector来创建一个注射器进行注入。

  1. function createInjector(modulesToLoad, strictDi) {
  2. // 依赖注入的模式:严格或者宽松
  3. strictDi = (strictDi === true);
  4. var INSTANTIATING = {},
  5. providerSuffix = 'Provider',
  6. path = [],
  7. // 哈希表,与对象字面量作为哈希表不同,它不仅支持字符串作为键值,还支持对象作为键值
  8. loadedModules = new HashMap([], true),
  9. providerCache = {
  10. // ... ...
  11. },
  12. providerInjector = (providerCache.$injector =
  13. createInternalInjector(providerCache, function(serviceName, caller) {
  14. // ... ...
  15. })),
  16. instanceCache = {},
  17. instanceInjector = (instanceCache.$injector =
  18. createInternalInjector(instanceCache, function(serviceName, caller) {
  19. // ... ...
  20. }));
  21. forEach(loadModules(modulesToLoad), function(fn) {
  22. if (fn) instanceInjector.invoke(fn);
  23. });
  24. return instanceInjector;
  25. function supportObject(delegate) {}
  26. function provider(name, provider_) {}
  27. function enforceReturnValue(name, factory) {}
  28. function factory(name, factoryFn, enforce) {}
  29. function service(name, constructor) {}
  30. function value(name, val) {}
  31. function constant(name, value) {}
  32. function decorator(serviceName, decorFn) {}
  33. function loadModules(modulesToLoad) {}
  34. function createInternalInjector(cache, factory) {
  35. function getService(serviceName, caller) {}
  36. function invoke(fn, self, locals, serviceName) {}
  37. function instantiate(Type, locals, serviceName) {}
  38. return {
  39. // ... ...
  40. };
  41. }
  42. }

createInjector的主体代码如下:

  1. strictDi = (strictDi === true);
  2. var INSTANTIATING = {},
  3. providerSuffix = 'Provider',
  4. path = [],
  5. loadedModules = new HashMap([], true),
  6. providerCache = {
  7. $provide: {
  8. provider: supportObject(provider),
  9. factory: supportObject(factory),
  10. service: supportObject(service),
  11. value: supportObject(value),
  12. constant: supportObject(constant),
  13. decorator: decorator
  14. }
  15. },
  16. providerInjector = (providerCache.$injector =
  17. createInternalInjector(providerCache, function(serviceName, caller) {
  18. if (angular.isString(caller)) {
  19. path.push(caller);
  20. }
  21. throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
  22. })),
  23. instanceCache = {},
  24. instanceInjector = (instanceCache.$injector =
  25. createInternalInjector(instanceCache, function(serviceName, caller) {
  26. var provider = providerInjector.get(serviceName + providerSuffix, caller);
  27. return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
  28. }));
  29. forEach(loadModules(modulesToLoad), function(fn) {
  30. if (fn) instanceInjector.invoke(fn);
  31. });
  32. return instanceInjector;

可以看到,主要是一些变量的定义,然后在forEach中执行loadModules依次加载模块,最后返回instanceInjector。

2、annotate(注解、解释)

  1. var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
  2. var FN_ARG_SPLIT = /,/;
  3. var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
  4. var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
  5. var $injectorMinErr = minErr('$injector');
  6. function anonFn(fn) {
  7. // For anonymous functions, showing at the very least the function signature can help in
  8. // debugging.
  9. var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
  10. args = fnText.match(FN_ARGS);
  11. if (args) {
  12. return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
  13. }
  14. return 'fn';
  15. }
  16. function annotate(fn, strictDi, name) {
  17. var $inject,
  18. fnText,
  19. argDecl,
  20. last;
  21. if (typeof fn === 'function') {
  22. if (!($inject = fn.$inject)) {
  23. $inject = [];
  24. if (fn.length) {
  25. if (strictDi) {
  26. if (!isString(name) || !name) {
  27. name = fn.name || anonFn(fn);
  28. }
  29. throw $injectorMinErr('strictdi',
  30. '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
  31. }
  32. fnText = fn.toString().replace(STRIP_COMMENTS, '');
  33. argDecl = fnText.match(FN_ARGS);
  34. forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
  35. arg.replace(FN_ARG, function(all, underscore, name) {
  36. $inject.push(name);
  37. });
  38. });
  39. }
  40. fn.$inject = $inject;
  41. }
  42. } else if (isArray(fn)) {
  43. last = fn.length - 1;
  44. assertArgFn(fn[last], 'fn');
  45. $inject = fn.slice(0, last);
  46. } else {
  47. assertArgFn(fn, 'fn', true);
  48. }
  49. return $inject;
  50. }

总结一下annotate:
1. 如果fn是一个函数,如果定义了fn.$inject属性,直接返回;如果未定义,则通过toString()得到其字符串形式,然后取出其中参数放在数组$inject中,这里涉及到依赖注入的严格模式
2. 如果fn是一个数组,即['service',function(service){}]形式,则将该数组的最后一项剔除,其余部分放在inject数组就是函数的真正依赖

3、createInternalInjector

  1. function createInternalInjector(cache, factory) {
  2. // 获取依赖的实例:如果在注册列表中存在,就返回,没有的话,调用工厂生成实例
  3. function getService(serviceName, caller) {
  4. if (cache.hasOwnProperty(serviceName)) {
  5. if (cache[serviceName] === INSTANTIATING) {
  6. throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
  7. serviceName + ' <- ' + path.join(' <- '));
  8. }
  9. return cache[serviceName];
  10. } else {
  11. try {
  12. path.unshift(serviceName);
  13. cache[serviceName] = INSTANTIATING;
  14. return cache[serviceName] = factory(serviceName, caller);
  15. } catch (err) {
  16. if (cache[serviceName] === INSTANTIATING) {
  17. delete cache[serviceName];
  18. }
  19. throw err;
  20. } finally {
  21. path.shift();
  22. }
  23. }
  24. }
  25. // 依赖注入的完成者
  26. function invoke(fn, self, locals, serviceName) {
  27. if (typeof locals === 'string') {
  28. serviceName = locals;
  29. locals = null;
  30. }
  31. var args = [],
  32. // 通过annotate方法得到需要注入的参数;
  33. $inject = createInjector.$$annotate(fn, strictDi, serviceName),
  34. length, i,
  35. key;
  36. for (i = 0, length = $inject.length; i < length; i++) {
  37. key = $inject[i];
  38. if (typeof key !== 'string') {
  39. throw $injectorMinErr('itkn',
  40. 'Incorrect injection token! Expected service name as string, got {0}', key);
  41. }
  42. // 通过locals或getService依次得到需要注入的参数的实例,放在args数组中;
  43. args.push(
  44. locals && locals.hasOwnProperty(key)
  45. ? locals[key]
  46. : getService(key, serviceName)
  47. );
  48. }
  49. // 如果fn是一个数组,即['service',function(service){}]形式,则取数组中最后一项作为执行函数fn
  50. if (isArray(fn)) {
  51. fn = fn[length];
  52. }
  53. return fn.apply(self, args);
  54. }
  55. // 实例化服务
  56. function instantiate(Type, locals, serviceName) {
  57. var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
  58. var returnedValue = invoke(Type, instance, locals, serviceName);
  59. return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
  60. }
  61. return {
  62. invoke: invoke,
  63. instantiate: instantiate,
  64. get: getService,
  65. annotate: createInjector.$$annotate,
  66. has: function(name) {
  67. return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
  68. }
  69. };
  70. }
  71. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注