Angular 项目架构

Angular Project Architecture

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

我是这样设计的。

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. 使用附加到 child 控制器作用域的承诺好吗?
  3. 如果我开始使用服务,它会改进我的代码吗?

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

为 child 控制器使用附加到作用域的承诺好吗?不要使用范围继承,它会导致很多烦人的问题。

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

如果我处在你的位置,我会这样做:

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

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

我会尽量根据自己的经验来回答你的问题。最近我构建了一个单页应用程序并重构了它的架构。

这是我的答案:

  1. 在控制器之间使用事件是一种好习惯吗? 恕我直言,这是在所有控制器之间共享信息的最灵活方式,即使它们具有独立的范围(使用 [=例如 10=] 或 $emit)。这称为观察者设计模式。但是,您可以使用服务而不是事件来在它们之间共享数据。如果您要使用 $rootScope,请小心,因为所有 $scope 都继承自 $rootScope
  2. 使用附加到子控制器作用域的 promise 好吗? 首先,您必须了解 scope inheritance 是如何工作的。你必须小心避免 JS 中的 属性 影子。其次,我会将 ChildController 中的 scope.loaded 中的所有逻辑移至 ChildService 等服务中。将业务逻辑(例如请求等)保留在服务而不是控制器中,将确保它可以被重用。 业务逻辑的分离是很好的设计原则。
  3. 如果我开始使用服务,它会改进我的代码吗?我在上面回答了这个问题。

此外,为了构建良好的体系结构,我阅读了 John Papa 撰写的 angular style guide

我建议进行以下更改:

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

希望对您有所帮助!

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

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

  1. 使用附加到子控制器作用域的 promise 好吗?

不,不是。在服务中使用承诺和解析数据。根本不要使用 $scope 而是使用 controllerAs 语法。 $scope 在 Angular JS 1.X 中也被弃用,因为它的使用会导致许多不同的范围继承问题。

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

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

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

  1. All the common logic in Main Controller and all other options in different controllers as the child of main controller.

在控制器中放置通用逻辑违反了所有 angular 风格指南。控制器应该只用于与视图相关的逻辑(数据绑定、验证……)。因为控制器中的代码不可重用,所以控制器中的代码越少越好。服务中的逻辑越多,应用程序的可扩展性就越高。

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

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

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

  1. To make sure data is loaded I am using promise attached to scope. So all the child controller will know data loaded.

使用承诺进行数据检索是一种很好的做法。但是,同样,将它保留在服务中比主控制器要干净得多。

  1. I have moved data updation part of all child controllers to main controller because all the updates happen in one object.

Child Controller emit/broadcast to communicate between child and main. So when update happens child will emit an event with data which will be captured by Main and it will do the update.

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

Is it a good practice to use events between controllers ?

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

另一方面,如果您将共享服务注入所有需要它的控制器,控制器之间的连接将变得明确和记录,并且它们的作用域在层次结构中的位置独立。这将使您的架构更易于维护,其中一个好处是也更易于测试。

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

is it good to use promise attached to scope for child controllers ?

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

(当然,不要为了减少变量的数量而盲目地这样做,尽量找到变量之间的语义联系,可能有意义地捆绑在一起。)

Will it improve my code if I start using services ?

我想上面的回答已经概括了这个问题的答案:是的。还有其他好处,但这种格式不适合太长的答案,所以我现在不会列出任何其他内容。

总而言之,以上这些提示并不是您当前代码的问题,但如果您正在寻找最佳架构,我认为您可以做得更好。

答案:

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

  2. $scope 已被弃用。

  3. 服务是不错的选择。服务允许我们在控制器等其他对象之间共享数据和行为。