对CommonJS、AMD、CMD简单粗暴的理解

  对于大型Web应用或者项目,动辄上万行的代码,给开发和后期维护带来了不小的麻烦。因此,需要有一种规范化的模块管理机制,帮助开发者集中处理模块的定义与调用关系。

  在ES6正式出台前,已经有不少人致力于推出适合Web开发的模块化管理标准,CommonJS、AMD和CMD就是其中的成功代表。

  以下为我查阅资料后,对三者最直观的理解:

CommonJS

  通常被应用于服务器,实现代表:NodeJS。NodeJS相信大家都不陌生,它的出现成功将Javascript应用到了服务器端,使得前段开发者也能较为省力得转向后端开发,而无需学习一门新语言。

  在服务器端,模块的加载和执行都在本地完成,因此,CommonJS并不要求模块加载的异步化。

模块定义与加载

  • 对于CommonJS,模块以文件为单位存在,模块实现全部位于该文件内部
  • 在文件末尾,需要把将要导出的方法添加到module.exports对象上
  • 随后在其他文件(模块)中,可以使用require()方法加载需要的模块,该方法要求一个参数:可以是一个模块名(此时加载的是默认提供的模块),或者是一个URL。如果是URL,其可以是相对路径或绝对路径,或者是一个指定的路径(由Node自行解析并寻找)。关于文件的后缀名,默认为“.js”,因此参数中可以省略后缀名;而如果指定的模块未发现,则会继续寻找以“.json”和“.node”为后缀的文件(其中以“.node”为后缀的文件将会以编译后的二进制文件格式解析)。

AMD

  AMD(异步模块加载)和CMD通常用于浏览器端,它们与CommonJS最明显的不同就是异步加载。AMD的实现代表是require.js,它也是require.js在推广过程中的附加产物。

模块定义与加载

  • AMD模块不一定以文件为单位,小模块集群也是允许的;但基本上在开发过程中,还是应当以文件的形式进行管理
  • 模块的定义由define()方法确定,该方法接受两个参数:
    • 一是当前模块的依赖模块,以数组形式传递
    • 二是当前模块的实现,以回调形式传递。一中的依赖通过参数传给回调。在回调末尾,以对象的形式返回需要公开的方法组。
  • 模块的配置使用require.config()方法,它接受一个对象类型的参数,该对象需要配置一些属性:baseUrl,paths,shim等
    • baseUrl:所有模块查找的根路径;未设置时默认是使用require.js的HTML文件所在目录。或者可以使用data-main属性在加载require.js的标签中定义根路径。
    • callback:当前依赖全部加载完成后的回调函数
    • config:将Application级别的配置信息传递给模块时使用。传递时使用module.config()方法。

      requirejs.config({
      config: {
      ‘bar‘: {
      	size:‘large‘
      },
      ‘baz‘: {
      	color: ‘blue‘
              }
          }
      });
      //bar.js直接使用module模块
      define(function (require, exports, module) {
          var size = module.config().size;
      });
      //baz.js使用了一个依赖数组,并要求一个特殊的依赖“module”
      define([‘module‘], function(module) {
          var color = module.config().color;
      });

      当“some/newmodule”调用了“require(‘foo‘)”,它将获取到foo1.2.js文件;而当“some/oldmodule”调用“`require(‘foo‘)”时它将获取到foo1.0.js。

    • exports:模块的输出
    • init:模块的初始化工作
    • paths:模块文件的路径。当paths中以/开头、或以.js结尾、或包含协议时(如http://...),其路径不在根路径下。
    • shim:需要未用define()方法定义的模块时使用。值为一组模块对象,每个对象分别有一些属性:deps,exports,init等。值得注意的是,shim只是定义了模块的依赖关系,仍然需要通过define+require的方式调用。
      • deps:模块的依赖数组
      • exports:模块的输出
    • map:对于给定的模块前缀,使用一个不同的模块ID来加载该模块。可以使用*号作为默认配置,且该配置可以被更具体的配置覆盖。

      requirejs.config({
      	map: {
      	    ‘some/newmodule‘: {
      	        ‘foo‘: ‘foo1.2‘
      	    },
      	    ‘some/oldmodule‘: {
      	        ‘foo‘: ‘foo1.0‘
      	    }
      	}
      });	
    • 更多参数请戳 参考链接

CMD

  CMD(通用模块加载)是sea.js在推广过程中的产出,它与AMD主要有以下几点区别(来自seajs的官方阐述):

  • 定位有差异。RequireJS 想成为浏览器端的模块加载器,同时也想成为 Rhino / Node 等环境的模块加载器。Sea.js 则专注于 Web 浏览器端,同时通过 Node 扩展的方式可以很方便跑在 Node 环境中。
  • 遵循的规范不同。RequireJS 遵循 AMD(异步模块定义)规范,Sea.js 遵循 CMD (通用模块定义)规范。规范的不同,导致了两者 API 不同。Sea.js 更贴近 CommonJS Modules/1.1 和 Node Modules 规范。
  • 推广理念有差异。RequireJS 在尝试让第三方类库修改自身来支持 RequireJS,目前只有少数社区采纳。Sea.js 不强推,采用自主封装的方式来“海纳百川”,目前已有较成熟的封装策略。
  • 对开发调试的支持有差异。Sea.js 非常关注代码的开发调试,有 nocache、debug 等用于调试的插件。RequireJS 无这方面的明显支持。
  • 插件机制不同。RequireJS 采取的是在源码中预留接口的形式,插件类型比较单一。Sea.js 采取的是通用事件机制,插件类型更丰富。
  • AMD提倡依赖前置,也就是在一开始就定义加载。而CMD则推崇依赖就近,即就在使用到模块的代码前面进行依赖加载。这里就需要注意了,使用requirejs会按照模块的依赖顺序进行加载,即模块不会按照代码里的顺序进行加载,可能造成意外地结果。

    这形成了两种截然不同的加载方式:“预加载”和“懒加载”。AMD提前将所有模块的所有依赖加载完成后,才开始执行主流程;而CMD是遇到一个依赖开始加载,完成后执行当前流程,遇到下一个依赖再次去加载,然后再执行下一步。当然,同一模块的依赖之间仍然是异步加载的。

模块定义与加载

  流程与AMD类似,不再赘述,只简单介绍seajs的API。

  • cache:查看当前模块系统中的模块信息
  • config:配置模块参数,参数列表:
    • alias:模块别名
    • base:根路径
    • paths:模块文件所在路径
    • vars:变量配置。比如需要在运行时确定模块路径的情况:

      seajs.config({
          // 变量配置
          vars: {
              ‘locale‘: ‘zh-cn‘
          }
      });
      define(function(require, exports, module) {
        var lang = require(‘./i18n/{locale}.js‘);
           //=> 加载的是 path/to/i18n/zh-cn.js
      });

      使用变量需要用花括号包围,如例中的{locale}。

  • data:查看 seajs 所有配置以及一些内部变量的值,可用于插件开发。当加载遇到问题时,也可用于调试。
  • resolve:利用模块系统的内部机制对传入的字符串参数进行路径解析。
  • use:加载模块。seajs.use(id/url/urlArray, callback)
时间: 2024-11-05 13:42:10

对CommonJS、AMD、CMD简单粗暴的理解的相关文章

简单粗暴地理解js原型链--js面向对象编程

简单粗暴地理解js原型链--js面向对象编程 原型链理解起来有点绕了,网上资料也是很多,每次晚上睡不着的时候总喜欢在网上找点原型链和闭包的文章看,效果极好. 不要纠结于那一堆术语了,那除了让你脑筋拧成麻花,真的不能帮你什么.简单粗暴点看原型链吧,想点与代码无关的事,比如人.妖以及人妖. 1)人是人他妈生的,妖是妖他妈生的.人和妖都是对象实例,而人他妈和妖他妈就是原型.原型也是对象,叫原型对象. 2)人他妈和人他爸啪啪啪能生出一堆人宝宝.妖他妈和妖他爸啪啪啪能生出一堆妖宝宝,啪啪啪就是构造函数,俗

如何快速简单粗暴地理解Python中的if __name__ == '__main__'

1. 摘要 通俗的理解__name__ == '__main__':假如你叫小明.py,在朋友眼中,你是小明(__name__ == '小明'):在你自己眼中,你是你自己(__name__ == '__main__'). if __name__ == '__main__'的意思是:当.py文件被直接运行时,if __name__ == '__main__'之下的代码块将被运行:当.py文件以模块形式被导入时,if __name__ == '__main__'之下的代码块不被运行. 2. 程序入口

commonjs amd cmd的区别

一篇博客告诉你三者的区别:http://zccst.iteye.com/blog/2215317 告诉你三者同requirejs seajs的区别:http://blog.chinaunix.net/uid-26672038-id-4112229.html 本人道听途生的: commonjs的规范在node还没有产生以前,就有了,commonjs作为一个后端的规范,虽然后端的Js以前发展缓慢,但是commonjs这个规范还是比较完善的,随着Node的普及,commonjs被完全遵从和实现,com

关于 CommonJS AMD CMD UMD 规范

CommonJS CommonJs是服务器端模块的规范,Node.js采用了这个规范. 根据CommonJS规范,一个单独的文件就是一个模块.加载模块使用require方法,该方法读取一个文件并执行,最后返回文件内部的exports对象. 例如: // foobar.js //私有变量 var test = 123; //公有方法 function foobar () { this.foo = function () { // do someing ... } this.bar = functi

commonjs AMD,CMD

CommonJS CommonJs 是服务器端模块的规范,Node.js采用了这个规范. 根据CommonJS规范,一个单独的文件就是一个模块.加载模块使用require方法,该方法读取一个文件并执行,最后返回文件内部的exports对象. 例如: // foobar.js //私有变量 var test = 123; //公有方法 function foobar () { this.foo = function () { // do someing ... } this.bar = funct

关于 CommonJS AMD CMD UMD

1. CommonJS CommonJS 原来叫 ServerJS, 是服务器端模块的规范,Node.js采用了这个规范. 根据CommonJS规范,一个单独的文件就是一个模块.加载模块使用require方法,该方法读取一个文件并执行,最后返回文件内部的exports对象. // foobar.js //私有变量 var test = 123; //公有方法 function foobar () { this.foo = function () { // do someing ... } thi

插件兼容CommonJS, AMD, CMD 和 原生 JS

模块标准 CommonJS CommonJS 有三个全局变量 module.exports 和 require.但是由于 AMD 也有 require 这个全局变量,故不使用这个变量来进行检测. 如果想要对外提供接口的话,可以将接口绑定到 exports (即 module.exports) 上. function MyModule() { // ... } if(typeof module !== `undefined` && typeof exports === `object`) {

关于 CommonJS AMD CMD UMD 规范的差异总结

一.CommonJS 主要是用于服务器端的规范,比如目前的nodeJS. 根据CommonJS规范,一个单独的文件就是一个模块.每一个模块都是一个单独的作用域,也就是说,在一个文件定义的变量(还包括函数和类),都是私有的,对其他文件是不可见的. // foo.js var request = require('request').default({ timeout: 4000 }); module.exports = function(){ this.re = ''; this.req = fu

好文要顶之 --- 简单粗暴地理解 JavaScript 原型链

原型链理解起来有点绕了,网上资料也是很多,每次晚上睡不着的时候总喜欢在网上找点原型链和闭包的文章看,效果极好. 不要纠结于那一堆术语了,那除了让你脑筋拧成麻花,真的不能帮你什么.简单粗暴点看原型链吧,想点与代码无关的事,比如人.妖以及人妖. 1)人是人他妈生的,妖是妖他妈生的.人和妖都是对象实例,而人他妈和妖他妈就是原型.原型也是对象,叫原型对象. 2)人他妈和人他爸啪啪啪能生出一堆人宝宝.妖他妈和妖他爸啪啪啪能生出一堆妖宝宝,啪啪啪就是构造函数,俗称造人. 3)人他妈会记录啪啪啪的信息,所以可