上一篇:[翻译]Angular的问题

下一篇:AngularJS实例教程(二)——作用域与事件

Angular中的模块机制

module

在AngularJS中,有module的概念,但是它这个module,跟我们通常在AMD里面看到的module是完全不同的两种东西,大致可以相当于是一个namespace,或者package,表示的是一堆功能单元的集合。

一个比较正式的Angular应用,需要声明一个module,供初始化之用。比如说:

随后,可以在HTML中指定这个module:

这样,就是以这个div为基准容器,实例化了刚才定义的module。

或者,也可以等价地这样,在这里,我们很清楚地看到,module的意义是用于标识在一个页面中可能包含的多个Angular应用。

这样可以在同一个页面中创建同一module的不同实例。两个应用互不干涉,在各自的容器中运行。

module的依赖项

除此之外,我们可以看到,在module声明的时候,后面带一个数组,这个数组里面可以指定它所依赖的module。比如说:

然后对应的HTML是:

好了,注意到这个例子里面,创建了两个module,在页面上只直接初始化了moduleA,但是从moduleA的依赖关系中,引用到了moduleB,所以,moduleA下面的TestCtrl,可以像引用同一个module下其他service那样,引用moduleB中定义的service。

到这里,我们是不是就可以把module当作一种namespace那样的组织方式呢,很可惜,它远远没有想的那么好。

这种module真的有用吗?

看下面这个例子:

我们在moduleA和moduleB中,分别定义了两个A跟B,然后,在moduleC和moduleD的时候中,分别依赖这两个module,但是依赖的顺序不同,其他所有代码完全一致,再看看结果,会发现两边的结果居然是不一致的。

再看看moduleE,它自己里面有一个A,然后结果跟前两个例子也是不同的。

照理说,我们对module会有一种预期,也就是把它当作命名空间来使用,但实际上它并未起到这种作用,只是一个简单的复制,把依赖的module中定义的东西全部复制到自己里面了,后面进来的会覆盖前面的,比如:

  • moduleC里面,来自moduleA的两个变量被来自moduleB的覆盖了
  • moduleD里面,来自moduleB的两个变量被来自moduleA的覆盖了
  • moduleE里面,来自moduleA的A被moduleE自己里面的A覆盖了,因为它的A是后加进来的

整个覆盖过程没有任何提示。

我们可以把module设计的初衷理解为:供不同的开发团队,或者不同的业务模块做归类约束用,但实际上完全没有起到这种作用。结果,不得不在下级组织单元的命名上继续做文章,不然在多项目集成的时候,就要面临冲突的风险。

更多的坑

不仅如此,这种module机制还为大型应用造成了不必要的麻烦。比如说,module不支持运行时添加依赖,看下面的例子:

假设上面是一个组件库,集中存放于components.js中,我们要在自己的应用中使用,必须:

现在假设这个components.js较大,我们不打算在首页引入,想在某个时候动态加载,就会出现这样的尴尬局面:

  • 主应用our.app启动的时候,必须声明所有依赖项
  • 但是它所依赖的module "some.components"的声明还在另外一个未加载的文件components.js中

关键问题就在于它不存在一个在our.app启动之后向其中添加some.components依赖的方式。我们预期的代码方式是类似这样:

也就是这段代码中注释掉的那句。但从现在看来,它基本没法做这个,因为他用的是复制的方式,而且对同名的业务单元不做提示,也就是可能出现覆盖了已经在使用的模块,导致同一个应用中的同名业务单元出现行为不一致的情况,对排错很不利。

在一些angular最佳实践中,建议各业务模块使用module来组织业务单元,基于以上原因,我个人是不认同的,我推荐在下一级的controller,service,factory等东西上,使用标准AMD的那种方式定义名称,而彻底放弃module的声明,比如所有业务代码都适用同一个module。详细的介绍,我会在另外一篇文章中给出。

此外,考虑到在前端体系中,JavaScript是需要加载到浏览器才能使用的,module的机制自身也至少应当包括异步加载机制,很可惜,没有。没有模块加载机制,意味着什么呢?意味着做大型应用有麻烦。这个可以用一些变通的方式去处理,在这里先不提了。

可以看到,Angular中的module并未起到预期作用,相反,还造成了一些麻烦。因此,我认为这是Angular当前版本中唯一一块弊大于利的东西,在2.0中,这部分已经做了重新规划,会把这些问题解决,也加入动态加载的考虑。

上一篇:[翻译]Angular的问题

下一篇:AngularJS实例教程(二)——作用域与事件