3

我当然错过了关于注射器的一些基本观点,但我不明白为什么会这样

angular.module('app').config(function ($provide) {
    ...
});

和这个

angular.module('app').config(function ($injector) {
    $injector.invoke(function ($provide) { ... });
});

按预期工作,而这

app.run(function($provide) {
    ...
});

会抛出

错误:[$injector:unpr] 未知提供者:$provideProvider <- $provide

从上面可以看出,config与提供者有一些特殊的关系,同时run处理实例,但我不确定是什么让config块如此特别。

因此,有没有办法到达$provide外部config块,例如angular.injector()(尽管它似乎也获得了提供者实例)?

这个问题,除了单纯的好奇之外,还有一些实际的考虑。在 1.4 中,所有$provide功能都暴露给模块,但在 1.3 中并非如此。

4

2 回答 2

5

config()函数的目的是允许您执行一些将影响整个应用程序的全局配置 - 包括服务、指令、控制器等。因此,该config()块必须在其他任何事情之前运行。但是,您仍然需要一种方法来执行上述配置并使其可用于应用程序的其余部分。做到这一点的方法是使用providers

提供程序“特别”的原因在于它们有两个初始化部分,其中一个与config()块直接相关。看看下面的代码:

app.provider('myService', function() {
    var self = {};    
    this.setSomeGlobalProperty = function(value) {
        self.someGlobalProperty = value;
    };

    this.$get = function(someDependency) {
        this.doSomething = function() {
            console.log(self.someGlobalProperty);
        };
    };    
});

app.config(function(myServiceProvider) {
    myServiceProvider.setSomeGlobalProperty('foobar');
});

app.controller('MyCtrl', function(myService) {
    myService.doSomething();
});

当您将提供程序注入config()函数时,您可以访问除函数之外的任何内容$get(从技术上讲,您可以访问该$get函数,但调用它不起作用)。这样你就可以做任何你可能需要做的配置。这是第一个初始化部分。值得一提的是,即使我们的服务被调用myService,这里也需要使用后缀Provider

但是当你将同一个提供者注入到任何其他地方时,Angular 会调用该$get()函数并注入它返回的任何内容。这是第二个初始化部分。在这种情况下,提供者的行为就像普通服务一样。

现在关于$provide$injectorconfig()由于它们是“配置服务”,因此您无法在块外访问它们对我来说很有意义。如果可以,那么您就可以在另一个服务使用它之后创建一个工厂。

最后,我还没有玩过 v1.4,所以我不知道为什么这种行为显然已经改变了。如果有人知道为什么,请告诉我,我会更新我的答案。

于 2015-04-24T20:43:05.623 回答
3

经过一些 Angular 注入器研究后,我能够对自己的问题给出详尽的答案。

本质上,$injector config块和provider构造函数以及$injector 其他任何地方都有两个具有相同名称的不同服务,它们在内部提供者/实例缓存中显式定义,以及$provide(这个是在提供者缓存中定义的,因此只能注入config) .

虽然通常不推荐,因为可能存在竞争条件,但可以将内部服务暴露给实例缓存,并使配置特定于配置$provide$injector在配置阶段结束后可用于注入:

app.config(function ($provide, $injector) {
  $provide.value('$providerInjector', $injector);
  $provide.value('$provide', $provide);
});

可能的应用程序正在随时配置服务提供者(如果可能)

app.run(function ($providerInjector) {
  var $compileProvider = $providerInjector.get('$compileProvider');
  ...
});

并在运行时定义新组件

app.run(function ($provide) {
  $provide.controller(...);
  ...
});
于 2015-11-14T02:31:29.437 回答