【问题标题】:Why create multiple AngularJS modules?为什么要创建多个 AngularJS 模块?
【发布时间】:2015-04-09 14:53:28
【问题描述】:

我很困惑。 AngularJS 需要在模块中创建服务、控制器和指令。但是这些服务、控制器和指令可以注入到任何其他服务、控制器或指令中,而不管它们所在的模块是什么!正确的?而且,除了 ng-app 之外,我还没有看到任何关心模块名称的 IDE 或工具。那么,为什么要创建多个模块?除了源代码的可读性之外,创建模块是否真的有其他好处?

示例...

(function(module) {

    var dir = function(something) {
        return {
        };
    };

    module.directive("myDirective", dir);

}(angular.module("pointlessModuleName")));

我已经尝试过寻找答案,但一直感到困惑...
Multiple Module in Angularjs

【问题讨论】:

  • 分离出所有组件,如服务、工厂、控制器等。与分离模块的代码中的命名空间相同
  • 当然,但是没有任何东西承认这个模块。 IDE 不关心模块名称。 Angular 不关心模块名称。我可以在不指定模块的情况下使用服务和控制器。那么,有什么意义呢?
  • 多个模块的最大好处是代码的可移植性。很容易将您的一个模块带到另一个项目或通过任意数量的在线资源找到模块
  • @G.Deward Angular 确实关心模块名称。例如,如果您想使用来自 3rd-party 库的任何内容,您必须首先通过其名称引用该库的模块。说你可以在不指定模块的情况下使用服务和控制器并不总是正确的。

标签: angularjs


【解决方案1】:

我也在想同样的事情,并决定走在狂野的一边,将所有内容合并到一个模块下。当然,几分钟后才知道为什么这不是一个好主意:) 所以我想花时间解释一下我认为模块在哪里发挥了非常好的作用,独立于“一般意见”。

我从以下方面着手:

// main.js - v0

var ServerData = require('./services/server-data')
var filters = require('./filters')

angular.module('ServerLoad', ['ngRoute'])
.factory('ServerData', ['$http', ServerData])
.filter('lastseen', function () {return filters.lastseen})
.config(['$routeProvider', function ($routeProvider) {
  $routeProvider
  .otherwise({
    redirectTo: '/servers'
  })
}])

现在我想添加一个显示服务器列表的视图。本质上,视图只不过是控制器和路由的组合,因此我将它们添加到代码中。这是我得到的(然后我会解释为什么这不是很好以及子模块如何解决这个问题):

// main.js - v1

var ServerListView = require('./views/server-list-view')       // <-- import view
var ServerData = require('./services/server-data')
var filters = require('./filters')

angular.module('ServerLoad', ['ngRoute'])
.factory('ServerData', ['$http', ServerData])
.controller('ServerListCtrl', ['ServerData', ServerListView])  // <-- add controller
.filter('lastseen', function () {return filters.lastseen})
.config(['$routeProvider', function ($routeProvider) {
  $routeProvider
  .when('/servers', {                                          // <-- add route
    controller: 'ServerListCtrl',                              //
    controllerAs: 'servers',                                   //
    templateUrl: 'assets/partials/server-list.html'            //
  })                                                           //
  .otherwise({
    redirectTo: '/servers'
  })
}])

虽然这肯定是一个有效的设置,但我不喜欢的是main.js 定义了controllerAstemplateUrl 属性。在我看来,这些属性真的应该在定义依赖它的代码的地方定义 --- './views/server-list-view',甚至可能在 ServerListView 类本身上。

因此,与您的 IIFE 有点类似,我向 ServerListView 添加了一个静态方法以将视图添加到模块:

// main.js - v2 (from v0)

var ServerListView = require('./views/server-list-view')       // <-- import view
// ...

angular.module('ServerLoad', ['ngRoute'])
// ...

ServerListView.setup(window.angular.module('ServerLoad'))      // <-- adds ctrl and route

// server-list-view.js - v2

function ServerListView (ServerData) {
  var scope = this
  // ...
}
module.exports = ServerListView

ServerListView.setup = function (module) {
  module
  .controller('ServerListCtrl', ['ServerData', ServerListView])
  .config(['$routeProvider', function ($routeProvider) {
    $routeProvider
    .when('/servers', {
      controller: 'ServerListCtrl',
      controllerAs: 'servers',
      templateUrl: 'assets/partials/server-list.html'
    })
  }])
}

我认为这看起来稍微好一些,但现在'ServerData' 的使用让我感到困扰。毕竟,它没有在任何地方的server-list-view.js 中声明。同样,如果视图需要一些额外的外部模块,我将不得不编辑 main.js 来添加它。这感觉不合适。

然后我突然想到,如果我可以编写一个 IIFE 以将 module 作为参数,为什么不让它以 angular 作为参数呢?然后它可以根据需要定义自己的模块并包含所需的所有依赖项。此外,如果您仍然热衷于单模块一切,那么只需使用 'ServerLoad' 模块名称并删除依赖项声明。这是唯一和全部的区别!

// server-list-view.js - v3

// ...

ServerListView.setup = function (angular) {
  angular.module('ServerLoad.ServerListView', ['ngRoute', 'ServerLoad'])
  // ...
}

所以,总而言之,我认为使用子模块的最大优势并不一定是其他人可以重用我的代码(我认为没有人会对我的服务器列表视图感兴趣),而是每一点代码可以独立存在,重用其他人的代码,而不需要主模块包含所有这些。 main.js 保持苗条,而 server-list-view.js 可以拉各种东西。

脚注。将ServerLoad 作为依赖项(到达ServerData 工厂)仍然看起来有点奇怪。当然,在版本 4 中,工厂也将存在于自己的子模块中;-)

【讨论】:

    【解决方案2】:

    据我所知,拥有多个模块的唯一原因是为了满足代码模块化,实现松耦合,以及将来易于维护。

    例如,您可能有一个应用程序模块,该模块依赖于实现特定功能区域的其他模块。这些模块不知道自己外部的任何东西,理想情况下不应该关心。

    假设您有一个数据存储模块,其中包含处理某些 Web 服务的 REST API 的服务和工厂。您基本上可以在多个应用程序中重用此模块。它本质上是即插即用的。将所有服务放入一个可以依赖注入的单独模块中只是一种很好地打包并使其可重用的方法。

    在我看来,您使用模块的代码示例并不理想,我也不会将 IIFE 限定为模块。我会做更多这样的事情:

    angular.module('dataRepo', []);
    // 'dataRepo' implementation left out for brevity
    
    // create a new angular app that depends on the 'dataRepo' module
    angular.module('myApp', ['dataRepo']);
    

    另外,这里有一个很好的article,你可以看看。向下滚动到按功能对模块进行分组的部分。

    【讨论】:

    • 当然,我明白了。但我正在等待一些东西来真正确认模块的存在。例如,在 Java 和 C# 中,有一个命名空间。 IDE 仅显示已包含的命名空间中可用的内容。我会假设一个模块应该以同样的方式工作。但是,我使用的所有 IDE(WebStorm、Brackets 等)都不会根据包含的模块过滤任何内容。而且,Module 在注入服务或控制器时不必添加任何前缀。就好像模块不存在一样。那么,有什么意义呢?
    • @G.Deward 你的意思是你在等待一个除了 human 之外的东西来确认模块的存在。您似乎对可读性论点不屑一顾,您在问题中承认了这一点。
    • 我编辑了我的答案以包含一个代码示例。当以这种方式使用时,它通过名称确认依赖模块的存在。不确定IDE识别模块名称是什么意思。您期待智能感知支持吗?
    • @Brett:感谢您的更新。我想我正在寻找除了可读性之外的其他东西。如果没有完成任何事情,将额外的语法放入文件通常是不好的。这似乎更适合发表评论。即使是上面的语法,包括dateRepo,这也可能是具有完全相同好处的服务。我看不出使用模块是如何专门完成任何事情的。
    • @G.Deward 即使dateRepo 只是一个服务。您可以简单地将其注入另一个模块这一事实对模块来说不是一个好的特性吗?通常,我能够跨应用程序重用代码只是因为我在模块中分离。单独的模块也使测试更加容易。
    【解决方案3】:

    可以创建一个可以做所有事情的大模块,但是 Angular 已经设置好,以便您可以将职责分配给不同的模块。

    ~除了可读性之外,创建模块真的有其他好处吗?

    您可能想了解一下 Angular 的不同功能。例如,可以将服务视为始终返回相同数据的单例。这对于创建 HTTP 请求以从 API 接收数据非常有用。

    创建了一个指令,以便它可以使用 jqlite 访问 DOM,这使得它非常适合创建 UI 组件。然后 Angular 有很多其他的东西你可以在一个模块中创建,比如常量。

    有大量关于 Angular 的介绍,其中解释了所有这些内容。如果你正在寻找一个好的 IDE,我个人使用 webstorm,它有很好的 Angular 支持。

    编辑 16.04.15

    我承认我有点误解/误读了你的问题。

    您将能够创建一个名为“app”的模块,其中包含所有指令、控制器等。让我从 Angular 网站 (https://docs.angularjs.org/guide/module) 链接到模块的优点:

    1. 声明式过程更容易理解。
    2. 您可以将代码打包为可重用的模块。
    3. 可以按任何顺序(甚至并行)加载模块,因为模块会延迟执行。
    4. 单元测试只需要加载相关模块,这样可以保持速度。
    5. 端到端测试可以使用模块来覆盖配置。

    第 1 点是您的可读性。

    2 表示可重用性。您将能够创建一个带有 html 小部件的库,例如,您可以在不同的项目中使用它。请注意,如果您使用第三方库,则说明您已经在使用模块系统。

    3 表示加载模块的灵活性。

    4+5 表示可测试性。如果您有一个包含所有代码的模块,您将无法轻松地对应用程序的各个部分进行单元测试。您可以更轻松地覆盖设置,还可以将模拟对象注入到您的模块中。

    【讨论】:

    • 这并没有真正的帮助。到目前为止,我已经构建了几个 Angular 应用程序。而且,我看过几个 Angular 教程(刚刚完成了 Scott Allen 的 Angular Playbook)。创建指令或服务不是问题。我正在尝试找到该模块的直接好处。
    猜你喜欢
    • 2014-10-16
    • 2016-04-10
    • 2010-11-27
    • 1970-01-01
    • 2012-07-28
    • 2022-10-18
    • 2014-05-31
    • 2017-10-23
    • 2020-05-20
    相关资源
    最近更新 更多