$提供外部配置块

$provide outside config blocks

我当然遗漏了一些关于注入器的基本要点,但我不明白为什么会这样

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

还有这个

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

按预期工作,而这

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

会抛出

Error: [$injector:unpr] Unknown provider: $provideProvider <- $provide

从上面可以看出,config与提供者有一些特殊的关系,而run处理实例,但我不确定是什么让config阻塞所以特别.

因此,是否无法到达 config 街区外的 $provide,例如使用 angular.injector() (尽管它似乎也获得了提供者实例)?

这个问题除了单纯的好奇之外,还有一些实际的考虑。在 1.4 中,所有 $provide 函数都暴露给模块,但对于 1.3 则不然。

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

提供程序 "special" 的原因在于它们有两个初始化部分,其中之一与 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() 函数并注入任何它 returns。那是第二个初始化部分。在这种情况下,提供者的行为就像普通服务一样。

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

最后,我还没有玩过 v1.4,所以我不知道为什么这种行为明显发生了变化。如果有人知道原因,请告诉我,我会更新我的答案。

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

本质上,$injector in config blocks and provider constructor functions and $injector everywhere else 是两个具有相同名称的不同服务,它们在内部 provider/instance 缓存中显式定义,连同 $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');
  ...
});

并在 运行-time

定义新组件
app.run(function ($provide) {
  $provide.controller(...);
  ...
});