【问题标题】:$provide outside config blocks$提供外部配置块
【发布时间】:2015-07-03 11:45:44
【问题描述】:

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

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

还有这个

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

按预期工作,而这

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

会扔

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

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

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

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

【问题讨论】:

    标签: angularjs internals angularjs-injector


    【解决方案1】:

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

    本质上,$injector in config blocks and provider constructor functions$injector everywhere else 是两个同名的不同服务,它们在内部提供程序/实例缓存上显式定义,与 $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(...);
      ...
    });
    

    【讨论】:

      【解决方案2】:

      config() 函数的目的是允许您执行一些将影响整个应用程序的全局配置 - 包括服务、指令、控制器等。因此,@ 987654322@ 块必须先运行。但是,您仍然需要一种方法来执行上述配置并使其可用于应用程序的其余部分。而做到这一点的方法是使用 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$injector。由于它们是“配置服务”,因此您无法在 config() 块之外访问它们对我来说很有意义。如果可以,那么您将能够在被另一个服务使用之后创建一个工厂。

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

      【讨论】:

      • 谢谢你,迈克尔,这是可以很好地为社区服务的高质量答案。目前我已经进步了一点,并且无法从答案中学到任何新东西。我希望有人能分享他关于 ng internals 的知识。我想我必须通过bootstrap$injector 并再次研究它们。
      • 在 1.4 中 module 最终公开了 $provide 提供的整个 API。在以前的版本中并非如此(至少缺少decorator)。
      猜你喜欢
      • 2019-08-15
      • 1970-01-01
      • 2017-01-27
      • 2017-07-21
      • 1970-01-01
      • 1970-01-01
      • 2017-09-02
      • 2018-07-01
      • 1970-01-01
      相关资源
      最近更新 更多