【问题标题】:Should an Angular service have state?Angular 服务应该有状态吗?
【发布时间】:2012-12-23 21:28:18
【问题描述】:

最近我和一些同事正在讨论 AngularJS 服务是否应该有状态。我们提出了一些支持和反对的论点,我想就这个主题获得更多的想法和反馈。在我的搜索中,我找到了this,但似乎没有提到任何明确的最佳实践。在无客户端的世界中,服务永远不应该保持状态,但我开始认为它可能是可接受的客户端,因为它是一个不同的问题。

服务保持状态的原因:

  1. 服务不会被多个线程访问。每个浏览器都有自己的服务实例。
  2. 允许服务仅保存它关心的状态,而不是将其存储在 rootScope 中。封装

服务不保持状态的原因:

  1. 服务不再是幂等的。调用函数可能会改变状态,因此根据服务的状态调用函数时可能会产生不同的结果。
  2. 我认为总的来说这会更容易测试。

在“用于保持状态的服务”部分中解决 #2 的一种方法是在包含应用程序当前状态的 rootScope 上设置一个 appState 对象。然后所有的状态将被收集在一个位置,然后你只需在你的服务中提取你需要的东西。我发现了这个并想知道

【问题讨论】:

    标签: service angularjs state


    【解决方案1】:

    这可能取决于您所说的“状态”是什么意思,但在许多情况下,我认为答案是肯定的:服务应该保持状态。

    例如,如果您有一个负责与 API 通信的服务,则该服务可以保持身份验证状态。

    顺便说一句,我不确定 AngularJS 服务的幂等性有多重要——它们是单例的,因此天生就有一些状态。您可以(并且在某些情况下必须)在服务上创建幂等方法,但这是一个单独的问题。

    【讨论】:

    • 关于保持身份验证状态的要点。至于使服务具有幂等性,就像您提到的那样,我的意思是具有幂等方法。感谢您的回答。
    • 将它保持在状态中的好处是您可以使用引用变量。正因为如此,您可以创建对复杂数据结构的清晰描述!
    【解决方案2】:

    在 AngularJS 中,服务 are passed in via factory function。基本上它们是可以包含某些状态的对象(例如,用于缓存或存储执行其操作所需的数据)。

    一个很好的解决方案可以同时考虑具有/不具有状态的缺点,即当服务(实际上可能是函数)返回包含状态的对象时。

    看看$http服务:你可以得到这个服务调用的实例

    var x = $http({url:'...'});
    

    然后调用

    var result = x.get() //actually `$http.get` is shortcut of this operation
    

    ngResource 相同:使用服务,您可以获得具有某种状态的对象,可以执行所需的操作。

    所以基本上我认为这是最好的选择:从某一点来看,您可以通过将可以通过操作修改的状态移动到单独的对象中来避免“副作用”,而不是存储在服务本身中,但可以在该对象中具有特定状态能够存储自定义信息(如身份验证信息等)。

    【讨论】:

    • 关于 $http 和 $resource 的优点。另外,我喜欢您关于仅存储不会被服务上调用的函数修改的状态的想法(可能在初始化服务时除外)。
    【解决方案3】:

    IMO 是的,服务可以有状态。我说“可以”作为服务可以被认为类似于经典的非客户端服务 - 提供者,但它也可以意味着完全不同的东西,在 angularJS 中。例如,作为应用程序中的 rootScope-y 单实例元素,它可以单独用于管理状态。在我的情况下,这使我能够确保状态结构在许多应用程序中是相同的,即使在引导过程中为每个应用程序定义了它们各自的状态结构,但当该模块发生更改时,会话状态之类的东西总是相同且更新的。

    【讨论】:

      【解决方案4】:

      服务不应该有状态的原因是当你有多个线程访问服务时它会导致竞争条件。

      服务中的一个常见问题是:

      1. 线程 1 写入状态
      2. 线程 2 写入状态
      3. 线程 1 从状态读取
      4. 线程 2 从状态读取

      线程 1 现在有错误的值。

      话虽如此,javascript 目前是单线程的,所以你不会遇到这样的线程访问问题。但是,如果我有一个服务,其中多个异步 $http 调用都写入同一个服务变量,我会担心。如果只有这样我晚上可以睡得更好,我会尝试编写我所有的服务方法,以便它们成为实际数据的传递。

      除了在服务中维护状态,您可以考虑将状态尽可能多地放在后端。可以维护和查询诸如“经过身份验证”甚至宽度和高度之类的内容。这可以打开一些可能性,允许用户离开应用程序,返回并发现他们的所有偏好仍然设置并登录。您可以在 cookie 中存储会话 ID 并将所有这些内容保存在后端。

      如果您确实采用了使用单独的对象来存储状态的方法,那么当状态中的某些内容发生变化时,您可能可以从服务中向它发送 $emit:how to emit events from a factory。这将产生一个很好的副作用,即让多个服务能够修改一个统一的应用程序状态,因为状态不会存储在任何一个服务中(或者更糟糕的是分散在多个服务中)。

      【讨论】:

      • 你自己说的,javascript 是单线程的,所以没有竞争条件,即使通过 webworkers 也不行,因为 webworkers 可以共享对对象的引用。你说的是后端,但是表示层具有与持久性无关的状态。
      猜你喜欢
      • 1970-01-01
      • 2012-01-04
      • 2015-12-15
      • 2021-01-02
      • 2018-01-14
      • 2011-09-11
      • 2021-10-27
      • 2010-11-27
      • 2018-12-25
      相关资源
      最近更新 更多