AngularJS 两个不同的 $injector
Posted
技术标签:
【中文标题】AngularJS 两个不同的 $injector【英文标题】:AngularJS two different $injectors 【发布时间】:2015-07-06 20:13:44 【问题描述】:今天发现,$injector
注入到 config 或 provider 与 $injector
注入到服务、工厂或控制器不同。
并且来自这个 $injectors 的 get()
函数的工作方式不同。
$injector
来自配置或提供者,不能get()
任何服务! $injector.get('myService')
抛出 Error: [$injector:unpr] Unknown provider: myService
,但 $injector.has('myService')
返回 true。这很奇怪。
来自服务或控制器的$injector
正常工作。
下面是一个代码示例以便更好地理解:
angular.module('app', [])
.provider('myProvider', function ($injector)
this.$get = ['$injector', function (serviceInjector)
return
providerInjector: $injector,
serviceInjector: serviceInjector
;
];
)
.service('myService', function () )
.controller('myCtrl', function ($scope, myProvider)
var providerInjector = myProvider.providerInjector;
var serviceInjector = myProvider.serviceInjector;
console.log(providerInjector === serviceInjector); // -> false
console.log(serviceInjector.has('myService')); // `serviceInjector` has `myService`
console.log(getMyService(serviceInjector)); // `serviceInjector` can get `myService`
console.log(providerInjector.has('myService')); // `providerInjector` has `myService` too!
console.log(getMyService(providerInjector)); // but `providerInjector` can't get `myService`! =(
function getMyService(injector)
try
injector.get('myService');
return "OK";
catch (e)
return e.toString();
);
Here is a plunker to play
谁能解释为什么有两种不同的注射器?
我如何使用 provider/config 中的 $injector 来注入服务(当然是在服务初始化之后)?
附:我使用角度 1.3.13
【问题讨论】:
你的问题有点不清楚。你想在提供者/配置中实现什么?能给个用例吗? 用例?例如:通过配置部分的 $injector 获取服务。或提供者。当然是在服务初始化之后。就我而言(显示起来非常复杂),我在配置部分向提供者添加了回调。在回调中我想使用我的服务。 DI 帮不了我,所以我使用 $injector。当服务已经初始化时,将从控制器调用此回调。 【参考方案1】:我在github上发现了这个问题:https://github.com/angular/angular.js/issues/5559
在config函数中,$injector是provider注入器,而在run函数中,$injector是instance注入器。
一个是配置阶段的 $injector(只有提供者和常量可访问),一个是运行阶段的 $injector。混淆可能是您认为 $injector 会修改自身以包含新内容,因为它跨越了从配置到运行的界限,但事实并非如此。它们是两个独立(尽管相关)的对象,具有自己的实例缓存。
造成这种二分法的更深入的原因可能来自对 $injector 内部结构的深度学习,但它似乎已经被 DRY-ed 非常硬核,并且两种类型的注入器几乎具有相同的行为,除了他们如何处理实例缓存中的“缓存未命中”。
我们将在 v2 中对注入器进行大修,因此这将在那里得到修复(摆脱配置阶段是注入器 v2 的目标之一)。
似乎真的有两个不同的注入器,并且 Angular 开发人员不会修复这种行为(在
我无法找到一种方法,如何在没有 hacky 技巧的情况下真正在配置块中获取 instance 注入器。所以,我写了一个可爱的提供者来解决这类问题。
.provider('instanceInjector', function ()
var instanceInjector;
function get()
return instanceInjector;
function exists()
return !!instanceInjector;
angular.extend(this,
get: get,
exists: exists
);
this.$get = function ($injector)
instanceInjector = $injector;
return
get: get,
exists: exists
;
)
// We need to inject service somewhere.
// Otherwise $get function will be never executed
.run(['instanceInjector', function(instanceInjector)])
【讨论】:
检查这个:the twin injectors【参考方案2】:好的。看完你的cmets,这是我的答案。
我在 plunk 中编辑了代码以使其工作,在调用 providerInjector.get() 时,代码应如下所示:
$scope.getMyServiceFromProviderInjector = function ()
try
myProvider.providerInjector.get('myServiceProvider');//here is change in provider name
return "OK";
catch (e)
return e.toString();
;
根据angular docs 引用以下配置和运行块:
配置块 - 在提供程序注册和配置阶段执行。只有提供者和常量 可以注入到配置块中。这是为了防止 在服务完全完成之前意外实例化服务 已配置。 运行块 - 在创建注入器后执行并用于启动应用程序。只有实例和常量可以 注入运行块。这是为了防止进一步的系统 在应用程序运行时进行配置。
这只是意味着,您无法在配置块中获取服务实例。
【讨论】:
@Harry Burns 请检查在您的 plunker 中有效的编辑代码 myProvider.providerInjector.get('myServiceProvider') 将只返回服务的提供者包装器,而不是服务本身。而且你没有回答我的第一个问题——为什么有两个 $injector?和有什么区别?以及如何在配置块中获取“service $injector”? 那么你不认为你有两个问题。 1. 为什么有两个不同的 $injector。 2.如何在配置中使用$inject。 ?对于第二个问题,答案是,您不能在配置中使用 $injector,因为在配置块中无法实例化服务。正如我在上面的答案中提到的那样。【参考方案3】:我不久前写了这篇文章,它解释了 AngularJS 的两个注入器的生命周期,即 providerInjector 和 instanceInjector。
http://agiliq.com/blog/2017/04/angularjs-injectors-internals/
【讨论】:
以上是关于AngularJS 两个不同的 $injector的主要内容,如果未能解决你的问题,请参考以下文章
如何解决 angularjs 未捕获的错误:[$injector:modulerr]?
AngularJS 1.2 $injector:modulerr
AngularJS 错误:$injector:unpr 未知提供者
错误:[$injector:unpr] 未知提供者:在 AngularJS 服务测试中
AngularJs中Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.3.15/