今天我发现,注入配置或提供商的$injector
与注入服务,工厂或控制器的$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();
}
}
});
有人可以解释为什么有两种不同的注射器吗?
如何从provider / config使用$ injector注入服务(当然,在服务初始化之后)?
P.S。我使用angular 1.3.13
答案 0 :(得分:8)
我在github上发现了这个问题:https://github.com/angular/angular.js/issues/5559
在config函数中,$ injector是提供程序注入器,其中在run函数中,$ injector是实例注入器。
配置阶段的$ inject(只有提供者和常量可访问),以及运行阶段的$ injector。混淆可能是你认为$ injector修改自己以包含新的东西,因为它跨越从配置到运行的线,但这不是真的。它们是两个独立的(尽管是相关的)对象,具有自己的实例缓存。
这种二分法的一个更深层次的原因可能来自对$ injector注射器内部的深入学习,但似乎它已经被干预了相当硬核,并且两种类型的注射器几乎共享相同的行为,除了他们如何处理"缓存未命中"在他们的实例缓存中。
我们将在v2中对喷油器进行大修,因此将在那里得到修复(摆脱配置阶段是喷油器v2的目标之一)。
看起来确实有两种不同的注入器,角度开发人员不会修复这种行为(在版本< 2.0中)。由于某种原因,没有人在$ injector文档中添加关于该方面的注释。
我无法找到一种方法如何在没有hacky技巧的情况下在配置块中真正获得实例注入器。所以,我写了一个可爱的提供者来解决这类问题。
.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){}])
答案 1 :(得分:1)
确定。看完你的评论后,这是我的答案。
我在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,以下引用了config和run blocks:
- 配置块 - 在提供程序注册和配置阶段执行。只有提供者和常量 可以注入配置块。这是为了防止 在服务完全之前意外实例化服务 配置。
- 运行块 - 在创建注入器后执行并用于启动应用程序。只有实例和常量才可以 注入运行块。这是为了防止进一步的系统 应用程序运行时的配置。
这只是意味着,您无法在配置块中获取服务实例。
答案 2 :(得分:0)
我前面写了这篇文章,它解释了AngularJS的两个注入器的生命周期,即providerInjector和instanceInjector。
http://agiliq.com/blog/2017/04/angularjs-injectors-internals/