角度项目架构

时间:2015-08-01 05:24:02

标签: javascript angularjs architecture

我正在构建一个角度的应用程序,它使用不同的API并提供用户选择它的选项将被记录并发送回服务器。

我的设计如下。

  • 主控制器中的所有常用逻辑和不同控制器中的所有其他选项作为主控制器的子控件。
  • 主控制器检索运行应用程序所需的所有数据。 由所有其他子控制器使用。
  • 为确保加载数据,我使用附加到范围的承诺。因此,所有子控制器都将知道加载的数据。
  • 我已将所有子控制器的数据更新部分移动到主控制器 因为所有更新都发生在一个对象中。
  • 子控制器发出/广播以在子和主之间进行通信。因此,当更新发生时,子将发出一个事件,其中包含将由Main捕获的数据,并且它将进行更新。
MainController {

  $scope.loaded = DataService.get();
  $scope.userOptions = {};
  $scope.$on('update',function(){
   updateUserOptions();
  })
}

ChildController {

  $scope.loaded.then(function(){
    //all logic of child controller
  }

  $scope.onselect = function(){
    $scope.$emit('update',data);
  }
}

问题

  1. 在控制器之间使用事件是一个好习惯吗?
  2. 使用附加到子控制器范围的承诺是否合适?
  3. 如果我开始使用服务,它会改进我的代码吗?

6 个答案:

答案 0 :(得分:18)

我会根据自己的经验尝试回答你的问题。最近我构建了一个单页面应用程序,并且我已经重构了它的架构。

以下是我的答案:

  1. 在控制器之间使用事件是一个好习惯吗?恕我直言,这是在所有控制器之间共享信息的最灵活方式,即使它们具有隔离范围(使用$broadcast或{ {1}}例如)。这称为观察者设计模式。但是,您可以使用服务而不是事件来在它们之间共享数据。如果您要使用$emit,请小心,因为所有$rootScope都继承自$scope
  2. 使用附加到子控制器范围的承诺是否合适?首先,您必须了解scope inheritance的工作原理。你必须小心避免JS中的属性阴影。其次,我会将$rootScopescope.loaded的所有逻辑移出ChildController之类的服务。保持服务而不是控制器中的业务逻辑(例如请求等)将确保它可以被重用。 业务逻辑的分离是很好的设计原则。
  3. 如果我开始使用服务,它会改进我的代码吗?我在上面回答了这个问题。
  4. 此外,为了建立一个良好的架构,我已经阅读了John Papa撰写的angular style guide

    我建议进行以下更改:

    1. 为确保加载数据,我使用附加到范围的承诺。因此所有子控制器都将知道加载的数据。。相反,我会发出一个自定义'加载'使用ChildService在MainController中的事件。之后,在ChildController中,我将使用$scope.$emit('loaded')来处理事件。
    2. 我会将$scope.$on('loaded', function(){})函数移动到服务中,并将其注入需要它的控制器中。
    3. 我希望有所帮助!

答案 1 :(得分:8)

在控制器之间使用事件是一种好习惯吗?不是数据共享的主要形式,但您可以使用它来通知系统事件,例如数据就绪。

使用附加到子控制器范围的承诺是否合适?不要使用范围继承,它会导致许多恼人的问题。

如果我开始使用服务,它会改进我的代码吗?是的。

这就是我要你所做的事情:

dataService - 此服务负责所有进/出的数据。每当发出数据请求时(无论哪个控制器要求数据),服务都会缓存数据(保存承诺就足够了)。所有进一步的请求都会获取缓存数据,除非他们指定需要新数据。每当数据更新(第一次或刷新)时,服务通过$ rootScope广播'dataReady'事件,主控制器和其他订户可以监听。 该服务还负责数据更新,当数据更新时,您还可以通过$ rootScope广播事件。 激活事件后,所有订阅者都会查询服务,并获取所需的数据。

控制器 - 避免使用控制器,使用具有隔离范围的指令,并使用属性在它们之间传递数据。通过这种方式,您可以确保每个指令都能获得所需的内容,而不是所有内容。指令可以使用属性,服务,广播/发射进行通信,或者如果它们紧密协作,则需要父母/兄弟姐妹。

答案 2 :(得分:7)

  1. 在控制器之间使用事件是一个好习惯吗?
  2. 不,不是,它将被Angular JS 2.0弃用。它还经常导致难以理解和调试的难以控制的事件。使用服务在控制器之间共享数据。 (将相同的服务注入多个控制器,服务然后保存数据,控制器绑定到该数据并自动同步)我写了blog post来解释这个用例。

    1. 使用附加于子控制器范围的承诺是否合适?
    2. 不,不是。使用promises并解析服务中的数据。不要使用$scope,而是使用controllerAs语法。在Angular JS 1.X中也弃用了$ scope,因为它的使用会导致范围继承的许多不同问题。

      1. 如果我开始使用服务,它会改进我的代码吗?
      2. YES!使用服务进行所有逻辑和数据操作。仅将控制器用于UI交互并将所有内容委托给服务。还可以使用ui-router来管理应用程序的状态。

答案 3 :(得分:5)

我不会直接回答你的问题,因为我还有其他一些评论。我认为你提到的方法不是构建角度应用程序的最佳方法。

  1.   

    主控制器中的所有常用逻辑和不同控制器中的所有其他选项作为主控制器的子级。

  2. 在所有角度样式指南中,将通用逻辑放在控制器中。控制器只应用于与视图相关的逻辑(数据绑定,验证,......)。因为控制器内的代码不可重用,所以控制器中的代码越少越好。您在服务中拥有的逻辑越多,您的应用程序就越具有可扩展性。

    修复:我建议您创建一个从服务器检索数据的服务,并根据需要在控制器中注入此服务。另请注意,这种方式可以提供更好的依赖关系管理,因为您可以准确跟踪哪些控制器需要哪些服务。

    1. 应尽可能避免使用嵌套控制器,因为angular会跟踪所有活动范围并在每个$apply()循环中重新评估它们。
    2. 修复:与#1相同,使用服务而不是主控制器。

      1.   

        为确保加载数据,我使用附加到范围的承诺。所以所有子控制器都会知道加载的数据。

      2. 使用数据检索承诺是一种很好的做法。但是,再一次,保持服务比主控制器更清洁。

        1.   

          我已将所有子控制器的数据更新部分移动到主控制器,因为所有更新都发生在一个对象中。

        2.   

          子控制器发出/广播以在子和主之间进行通信。因此,当更新发生时,子将发出一个事件,其中包含将由Main捕获的数据,并且它将进行更新。

          修复:使用具有update功能的服务而不是事件。事件更难调试和跟踪。并且您需要在销毁控制器时取消注册事件处理程序。如果你可以使用函数/ promise而不是事件,那么通常是一个更好的主意。

答案 4 :(得分:5)

  

在控制器之间使用事件是一种好习惯吗?

您当前设置的一个问题是您隐含地依赖于控制器的层次结构(事实上一个是另一个的孩子) - 因为您emit事件,只有更高的范围在层次结构上可以捕获它。除了是一个隐式连接(开发人员必须记住),这也限制了他对此功能的可扩展性。

另一方面,如果您将共享服务注入到需要它的所有控制器中,那么控制器之间的连接将变得明确并记录,并且它们的范围在层次结构中的位置是独立的。这将使您的架构更易于维护,并且还可以更容易地进行测试。

您仍然可以使用服务实现观察者模式。

  

使用附加到子控制器范围的承诺是否合适?

其他答案中指出的污染范围问题是有效的。这是为什么最好限制附加到作用域的对象数量,以及在作用域中使用对象作为变量包而不是直接将所有变量附加​​到作用域的原因之一。 (有关这些原因的解释,请参阅有关“always having a . in your bindings”的讨论。)

(当然,不要盲目地只是为了减少变量的数量,尝试找到可能有意义地捆绑在一起的变量之间的语义连接。)

  

如果我开始使用服务,它会改进我的代码吗?

我认为上述答案已经勾勒出了答案:是的。还有其他好处,但这种格式不适合太长的答案,所以我现在不会列出任何其他内容。

总而言之,上述指针目前与您的代码不存在 big 问题,但如果您正在寻找最佳架构,我认为您可以做得更好。

答案 5 :(得分:2)

答案:

  1. 不,它很快就会被弃用。

  2. $ scope已被弃用。

  3. 服务是一个很好的选择。服务允许我们跨控制器等其他对象共享数据和行为。