【问题标题】:AngularJS injecting a factory into a providerAngularJS 将工厂注入提供者
【发布时间】:2016-02-18 06:31:16
【问题描述】:

我正在构建一个必须使用provider 配方的模块,因为它需要在运行前进行配置。我对模块化我的代码很感兴趣,所以我想将一些服务注入到提供程序中。我知道将providers 注入其他providers 很简单,但对于我想要实现的目标来说似乎有点过头了,所以我想注入factory

据我了解,在运行时使用$injector 可以让我们通过angular 的createInternalInjector 方法访问instanceCache,该方法返回已实例化的服务。

在配置阶段使用$injector 时,您可以访问包含未实例化服务的providerCache

我觉得这个假设一定是不正确的。在下面的代码中,$injector 在提供程序中使用,但通过在应用程序运行阶段调用的函数。我希望能够访问instanceCache,但我只能通过$injector.get 方法访问providerCache

_tudModule.factory('wfTabletUsageDataCache', [
        function () {
            return {
                addToLog: fn () { … }
            }
        }
])


_tudModule.provider('$tabletUsageData', [
    '$injector', function $tabletUsageDataProvider ($injector) {

    function getCacheFactory() {
       return $injector.get('wfTabletUsageDataCacheProvider').$get();
    }

    function logInteraction(state, buttonId) {
        getCacheFactory().addToLog();           // fn() called
    }
]);

provider 中的$injector 会禁用对instanceCache 的访问吗?即使提供程序中的方法在config 阶段没有运行?

另外,我之前没有见过我使用$injector.get('wfTabletUsageDataCacheProvider').$get() 的方法。虽然可行,但这是实现此类功能的坏方法吗?

感谢您的任何指导。

【问题讨论】:

    标签: javascript angularjs


    【解决方案1】:

    你的假设是对的。您错过的是有两种不同的注入器,分别用于服务提供者和服务实例。一旦您将提供程序注入器注入provider,即使在配置阶段之后,它也会继续处理提供程序。您也可以查看this answer 进行澄清。

    使用$injector.get('someProvider').$get() 将返回一个与instanceCache 无关且不是单例的新服务实例。 IE。

    $injector.get('someProvider').$get() !== $injector.get('someProvider').$get();
    

    $get 的背后并没有什么神奇之处,它只是一个构造函数,注入器没有办法或理由来跟踪它的调用。

    对于当前代码factory 可以安全地使用而不是provider。如果必须在config 中配置提供程序,则所有与实例相关的代码都应转到$get(因为factory 只是provider 的糖语法,只有$get 方法)。

    【讨论】:

    • 您好,感谢您的回复。所有实例代码都应该转到$get,你的意思是provider('provider', function () { return {$get: function () { ... } } });?感谢您的帮助!
    【解决方案2】:

    在配置阶段,(config() 块或提供程序)您可以注入 providersconstants,而不是工厂、服务或值。如果提供者对你来说太过分了,你可以使用一个常量。

    这样的东西可以工作

    _tudModule.constant('wfTabletUsageDataCache', {
      addToLog: function () { ... }
    });
    
    _tudModule.provider('$tabletUsageData', [ 'wfTabletUsageDataCache',
      function (wfTabletUsageDataCache) {
         wfTabletUsageDataCache.addToLog(...)
      }
    ]);
    

    在配置阶段使用$injector 时,您可以访问包含未实例化服务的providerCache

    看来您是正确的,但这种用法没有记录在案,通常不鼓励使用。 $injector 是一个服务,不应该注入到提供者中。


    另外,我之前使用$injector.get('...').$get()的方法我没见过。

    提供者是定义 Angular 服务的最低级别的方法。所有.service().factory().value() 定义都可以使用.provider() 重写。根据定义,当提供者被实例化时,它必须公开一个$get 方法,该方法是可注入的并负责返回服务的实例。

    这就是您在这里看到的。您正在使用$injector.get(...) 检索(并实例化)提供程序,然后使用$get() 方法创建服务实例。然而,这通常发生在幕后,$get() 方法并不意味着手动调用。

    您实际上是在尝试破解不允许在运行阶段之前实例化服务的限制。不建议这样做。

    【讨论】:

    • 太棒了!谢谢您的帮助。您认为在这种情况下注入constant 或在提供者的$get 函数中定义方法(如另一个答案中所述)更可取吗?
    • 如果你的 wfTabletUsageDataCache 没有依赖项(即你不需要注入任何东西来使其工作),那么一个常量就可以了。我不确定我是否完全理解其他答案的建议,但据我所知,模块化用于配置服务(即在提供程序中)的功能的唯一“正确”方法是一个常量。
    • 另外值得注意的是,如果您在配置$tabletUsageData 时不需要wfTabletUsageDataCache,那么您可以将其保留为工厂(或其他任何东西)并将其注入提供者的$get 方法而不是比提供者构造函数本身。
    • 太棒了!非常有帮助。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2021-07-17
    • 2014-01-19
    • 2015-07-22
    • 2014-12-19
    • 2020-11-18
    • 2014-04-20
    • 1970-01-01
    • 2016-10-07
    相关资源
    最近更新 更多