角度项目架构

Sre*_*akh 31 javascript architecture angularjs

我正在构建一个角度的应用程序,它使用不同的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);
  }
}
Run Code Online (Sandbox Code Playgroud)

问题

  1. 在控制器之间使用事件是一种好习惯吗?
  2. 使用附属于儿童控制器范围的承诺是否好?
  3. 如果我开始使用服务,它会改进我的代码吗?

小智 18

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

以下是我的答案:

  1. 在控制器之间使用事件是一种好习惯吗?恕我直言,这是在所有控制器之间共享信息的最灵活方式,即使它们具有隔离范围(使用$broadcast$emit例如).这称为观察者设计模式.但是,您可以使用服务而不是事件来在它们之间共享数据.如果您要使用$rootScope,请小心,因为所有$scopes都继承$rootScope.
  2. 使用附属于儿童控制器范围的承诺是否好?首先,您必须了解范围继承的工作原理.你必须小心避免JS中的属性阴影.其次,我将所有的逻辑从搬出scope.loadedChildController这样的服务ChildService.保持服务而不是控制器中的业务逻辑(例如请求等)将确保它可以被重用.业务逻辑的隔离是良好的设计原则.
  3. 如果我开始使用服务,它会改进我的代码吗?我上面回答了这个问题.

另外,为了建立一个好的建筑,我读过John Papa写的这个角度风格指南.

我建议进行以下更改:

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

我希望有所帮助!


Ori*_*ori 8

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

使用附属于儿童控制器范围的承诺是否好?不要使用范围继承,它会导致许多恼人的问题.

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

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

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

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


tom*_*jan 7

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

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

  1. 使用附属于儿童控制器范围的承诺是否好?

不,这不对.使用promises并解析服务中的数据.不要使用$scope,而是使用controllerAs语法.Angular JS 1.X中也弃用了$ scope,因为它的使用会导致范围继承的许多不同问题.

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

是!使用服务进行所有逻辑和数据操作.仅将控制器用于UI交互并将所有内容委托给服务.还ui-router用于管理应用程序的状态.


Gaa*_*far 5

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

  1. 主控制器中的所有通用逻辑和不同控制器中的所有其他选项作为主控制器的子控制器.

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

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

  1. 应尽可能避免使用嵌套控制器,因为angular会跟踪所有活动范围并在每个$apply()循环中重新评估它们.

修复:与#1相同,使用服务而不是主控制器.

  1. 为了确保加载数据,我使用附加到范围的承诺.因此所有子控制器都将知道加载的数据.

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

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

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

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


dol*_*ldt 5

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

您当前设置的一个问题是您隐式依赖于控制器的层次结构(事实上一个是另一个的子节点) - 因为您emit只有事件,层次结构中较高的范围才能捕获它.除了是隐式连接(开发人员必须记住)之外,这也限制了此功能的可扩展性.

另一方面,如果将共享服务注入到需要它的所有控制器中,则控制器之间的连接将变得明确并记录,并且它们的范围在层次结构中的位置是独立的.这将使您的架构更易于维护,并且还具有更易于测试的额外好处.

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

使用附属于儿童控制器范围的承诺是否好?

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

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

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

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

总而言之,这些上述指针目前对您的代码来说不是问题,但如果您正在寻找最佳架构,我认为您可以做得更好.