浅谈 JavaScript 模块定义规范
JS 模块定义常见的有三种方式,即 AMD, CMD 和 CommonJS。其实还有一个 UMD,他是 CommonJS 和 AMD 揉和在一起而已。不过这些都 out 了,拥抱 ES6 吧。话虽这么说,你让那些不用 ES6 不用 babel 的怎么活,所以还是要了解下滴。
CommonJS
CommonJS 是服务端即 Node.js 采用的模块化方案,我们应该都很熟悉了。例如:
这个过程是同步的,只有成功加载 fs
后才能执行后面的步骤。但在服务器文件都在本地,所以这个问题不大。但这个在浏览器就不合适了,如果文件加载耗时很长,将导致一直等待。
AMD
AMD 全称 Asynchronous Module Definition,意思就是异步模块定义。
用法如下:
math 模块的加载和 math.add()
方法的执行不是同步的,这样浏览器就不会假死。
RequireJs 和 CurlJs 实现了 AMD 规范,将他们嵌入网页,就可以在浏览器端进行模块化编程了。
关于 AMD 的详细模块定义可以参考wiki)。这里给出 Underscore 的 AMD 定义方法:
CMD
CMD 全称 Common Module Definition,意思就是通用模块定义。。
对于依赖的模块,AMD 是提前执行,而 CMD 是延迟执行。AMD 推崇依赖前置,而 CMD 则推崇依赖就近。例如:
CMD 的主要实现是 SeaJS
AMD 预先加载所有依赖,使用的时候才去执行,速度快,可以并行加载多个模块。但这就需要开发的时候把全部依赖都提前定义,不便于开发和阅读,而且部分依赖(弱依赖)可能只在少数情况下使用。
CMD 只有在真正需要的时候才去加载依赖,使用的时候才去定义执行,但这个加载逻辑偏重,耗性能。
UMD
UMD 全称 Universal Module Definition。
UMD 是 AMD 和 CommonJS 的揉和,他优先使用 CommonJS 的加载方式,其次才使用 AMD 的加载方式。
例如:
其实就是一个服务端和浏览端通用的模块解决方案。
ES6 Module
ES6 在语言规格的层面上实现了模块功能,并且实现非常简单,完全可以替代现有的模块加载方案,成为浏览器和服务端都通用的模块解决方案。
这种做法将只在 fs 模块加载3个方法,其他方法不会进行加载。ES6 可以在编译时就完成模块加载,效率比 CommonJS 的加载方式高。
在浏览器中使用 ES6 模块的语法:
目前 Node 默认模块格式是 CommonJS,ES6 的模块方案还不支持,但可以通过 babel 来使用。
现在推荐做法是广泛使用 ES6 甚至 ES7 来书写 JavaScript 以提高开发效率,再使用 babel 转码就好了。所以前后端我们也都可以使用 ES6 的 Module 来进行。其他的模块加载方案应该会渐渐退出历史舞台。