访问可能存在或可能不存在的Angular服务

Joe*_*lay 6 javascript angularjs

我正在开发一个非常模块化的Angular项目 - 可以使用Webpack为不同的客户启用和禁用应用程序的各个部分.到目前为止,这个结构对我来说很有效,但我遇到的一个问题是如何处理可能并不总是存在的服务.

我目前的解决方案非常简单 - 我$injector.has()用来检查服务当前是否存在,如果是,我用$injector.get()它来抓住它:

function initialize($injector) {
    if ($injector.has("barcode")) {
        let barcode = $injector.get("barcode");

        // Do stuff with the barcode service
    }
}
Run Code Online (Sandbox Code Playgroud)

这似乎有效 - 但是,我找不到关于这种模式的使用的信息,以及它是否有任何潜在的缺点.

所以,我的问题是:

  • 我应该注意使用注射器有什么注意事项吗?
  • 这样做有更好/更惯用的方法吗?

JcT*_*JcT 3

这可能是实现您想要的目标的最佳方式;但是,在执行此操作时,请注意您正在从依赖项注入(DI) 转向服务定位器模式。

Angular 2 文档中的以下内容非常相关(强调我的):

除非我们真正需要它,否则我们会避免使用这种技术。它鼓励了一种粗心的抓包方法,就像我们在这里看到的那样。解释、理解和测试都很困难。我们无法通过检查构造函数知道这个类需要什么或者它将做什么。它可以从任何祖先组件获取服务,而不仅仅是它自己的组件。我们被迫深入研究其实现以发现它的作用。

当框架开发人员必须通用且动态地获取服务时,他们可以采用这种方法。

(旁白:值得一读的是Angular 2 中的依赖注入即将到来的内容——可选依赖项、工厂提供程序等。)

Angular 1关于此事的文档提到它与德米特法则相冲突(当然,这更多的是一个指导方针,而不是一条法则,对吧?)。

无论如何,还需要注意一些额外的事情:

  • 使用此函数时,您不会收到循环依赖项的警告(通过抛出错误);事实上,这通常是人们用来绕过这些警告的技术。

  • 由于您现在除了注入内容之外还依赖于 $injector,因此您的单元测试要么需要模拟 $injector,要么使用类似module('moduleThatIsUsingInjectorExplicitly', function($provide) { $provide.value('barcode', barCodeMock);}.

  • 正如上面引用中提到的,您的代码会不太清晰,因为这些“可选”依赖项没有在通常的地方定义。

还有大量关于服务定位器模式的其他读物,并将其与 DI 进行对比。很有趣,但对我们的实际影响可能有限,特别是因为 JavaScript 缺乏 Interface/Abstract 和 Angular 1 的 DI 实现意味着真正的差异点较少。