AMD,CMD,CommonJS和UMD
由于项目中引入的echarts的文件很大,requirejs通常会加载超时,因此必须单独加载才能加载echarts的各种图表。但是,支持echarts随附的在线构建工具生成的AMD标准的模块会报告错误,因此我必须使用echarts的全局函数来加载requirejs。借此机会了解AMD,CMD,CommonJS和UMD的规格以及它们之间的差异。

Javascript模块化
在您理解这些规范之前,让我们首先了解什么是模块化。
模块化是指在解决复杂问题或一系列其他问题时,根据分类思想系统地分解问题。模块化是一种处理复杂系统的方法,该系统被分解为具有更多代码结构和更高可维护性的可管理模块。可以想象,庞大的系统代码在集成和优化后可以细分为高度逻辑的模块,这对于软件来说是有意义的。对于软件行业:无论系统多大,软件的去耦合都使管理,开发和维护更简单。
模块化也有一些定义:模块化是软件系统的属性,该软件被分解为一组高度衔接,低耦合的模块。因此,在理想状态下,我们只需要完成一些核心业务逻辑代码,其他方面的依赖就可以由已经编写模块的人直接加载使用。
首先,由于它是模块化设计,因此作为模块化系统所需的函数:
定义包的模块。
定义新模块对其他模块的依赖性。引入了对其他模块的支持。
这样考虑之后,那么总会有东西来构建模块化的规范系统,否则各种模块加载方法只会使局变得更加混乱。然后是JavaScript中非传统模块开发方法的一些规范。CommonJS模块规范,AMD(异步模块定义),CMD(公共模块定义)等。
CommonJS
CommonJS是服务器端模块的规范,而Node.js使用此规范。
根据CommonJS规范,单个文件是一个模块。加载模块使用require方法,该方法读取并执行文件,最后返回文件内的导出对象。
E.g:
// foobar.js
// private variable
var test = 123;
//public method
function foobar () {
this.foo = function () {
// do someing ...
}
this.bar = function () {
//do someing ...
}
}
//The methods and variables on the exports object are public.
var foobar = new foobar();
exports.foobar = foobar;
//require method reads the js file by default, so you can omit the js suffix
var test = require('./boobar').foobar;
test.bar();
CommonJS加载模块是同步的,因此只有加载完成才能执行以下操作。Node.js主要用于服务器编程。加载的模块文件通常具有本地硬盘,因此加载速度更快,无需考虑异步加载方法,因此CommonJS规范更适合。但是,如果是浏览器环境,则要从服务器加载模块,必须使用异步模式。因此,有一个AMD CMD解决方案。
AMD and RequireJS
AMD
AMD是“异步模块定义”的缩写,表示“异步模块定义”。
AMD设计了一个简单的写模块API:define(id?,dependency?,factory);
- 第一个参数id是代表模块ID的字符串类型,并且是可选的。如果不存在,则默认情况下应将模块ID定义为加载程序中所请求脚本的标识符。如果存在,则模块ID必须是顶级或绝对标识符。
- 第二个参数,dependencies是当前模块所依赖的数组文字,由模块标识。
- 第三个参数factory是需要实例化的函数或对象。
通过组合参数,此简单的API可以处理各种应用程序场景,如下所述。
//Defining a module without dependencies
define( {
add : function( x, y ){
return x + y ;
}
} );
// Defining a module with dependencies
define(["alpha"], function( alpha ){
return {
verb : function(){
return alpha.verb() + 1 ;
}
}
});
// Defining data object modules
define({
users: [],
members: []
});
//Named module
define("alpha", [ "require", "exports", "beta" ], function( require, exports, beta ){
export.verb = function(){
return beta.verb();
// or:
return require("beta").verb();
}
});
// Packaging module
define(function(require, exports, module) {
var a = require('a'),
b = require('b');
exports.action = function() {};
} );
格式与Node.js相同,除了函数层不同:使用require获取依赖项模块,然后导出以导出API。
除了定义之外,AMD还保留了关键字require。Require是规范保留的全局标识符,可以或不可以作为模块加载器来实现。
模块加载
require([module], callback)
AMD模块化规范使用全局或本地require函数来加载一个或多个模块,并且所有模块均在回调函数完成后加载。
他们之中:
[module]:是一个数组,其中的成员是要加载的模块;
callback:是模块加载后的回调函数。
例如:加载math模块,然后调用方法math.add(2,3);
require(['math'], function(math) {
math.add(2, 3);
});
RequireJS
RequireJS是遵循AMD规范的前端模块化管理工具库,由AMD规范的创始人James Burke编写。
RequireJS的基本思想是通过一个函数加载所有必需的或依赖的模块实现,然后返回一个新的函数(模块)。我们有关新模块的所有业务代码都在该函数内部。自内部以来,它也可以不受限制地使用已加载的模块。
然后,脚本下的main.js是指定的主代码脚本文件,所有从属模块代码文件将从文件中异步加载到执行中。
Define用于定义模块,RequireJS要求将每个模块放置在单独的文件中。根据是否有其他模块将其分为独立模块和非独立模块。
Independent module, does not depend on other modules. Direct definition:
define({
method1: function(){},
method2: function(){}
});
Also equivalent to
define(function() {
return {
method1: function(){},
method2: function(){}
}
});
与其他模块有依赖关系的非独立模块。
define([ 'module1', 'module2' ], function(m1, m2) {
...
});
或者:
define(function(require) {
var m1 = require('module1'),
m2 = require('module2');
...
});
简要介绍RequireJS的实现,它的require实现只是在require之后提取模块名称,并将其放入依赖项中。
Require方法调用模块
当需要调用模块时,其参数类似于定义。
require(['foo', 'bar'], function(foo, bar) {
foo.func();
bar.func();
} );
在加载两个模块foo和bar以实现特定过程之后,将执行回调函数。
当然,与前面的示例一样,require调用模块在define definition模块内部执行。
define(function(require) {
var m1 = require( 'module1' ),
m2 = require( 'module2' );
...
});
定义和要求这两个定义模块,调用该模块的方法称为AMD模式,定义模块很明确,它不会污染全局变量,并且清楚地显示出依赖关系。AMD模式可以在浏览器环境中使用,并允许模块的非同步加载,以及根据需要动态加载模块。
官方网站(http://www.requirejs.org/)
API(http://www.requirejs.org/docs/api.html)
CMD和SeaJS
CMD是SeaJS在升级过程中模块定义的标准化输出。
对于从属模块AMD提前执行,CMD被延迟执行。但是,RequireJS已从2.0更改为最新版本,并且可以延迟(取决于编写方式,处理方法不会通过)。
CMD提倡依赖,AMD提倡依靠前置。
//AMD
define(['./a','./b'], function (a, b) {
/ / Dependency writes well at the beginning
a.test();
b.test();
});
//CMD
define(function (requie, exports, module) {
/ / Dependency can be written nearby
var a = require('./a');
a.test();
...
//soft dependency
if (status) {
var b = requie('./b');
b.test();
}
});
尽管AMD还支持CMD,但依赖关系前置是官方文档的默认模块定义。
AMD的API默认值是一次性使用,CMD严格区分单个责任。例如:AMD必须是全球性和本地性的。CMD中没有全局要求,它提供seajs.use()来加载和启动模块系统。CMD中的每个API都是简单而纯净的。
UMD
UMD是AMD和CommonJS的组合
AMD模块是根据浏览器优先原理开发的,并且模块是异步加载的。
CommonJS模块是在服务器的第一原理上发展而来的,它具有同步加载函数,并且不需要包装其模块(未包装的模块)。
这迫使人们想出另一个更通用的模型UMD(通用模块定义)。希望解决跨平台的解决方案。
UMD首先确定是否支持Node.js模块。如果存在,则使用Node.js模块模式。
在判断是否支持AMD(如果存在)时,将使用AMD方法加载模块。
(function (window, factory) {
if (typeof exports === 'object') {
module.exports = factory();
} else if (typeof define === 'function' && define.amd) {
define(factory);
} else {
window.eventUtil = factory();
}
})(this, function () {
// module ...
});
模块化:模块化是指在解决复杂问题时根据分类思路系统地分解问题。可以想象,可以想象到巨大的系统代码并将其集成到高度逻辑化的模块中。软件是什么意思。
模块化系统所需的函数:
1.定义打包的模块
2.定义新模块对其他模块的依赖性
3,可以引入对其他模块的支持
AMD模块规范:实际上,它是一个异步模块定义。所有模块将异步加载。模块加载不会影响后续的语句操作。所有依赖于某些模块的语句都放置在回调函数中。
AMD规范以以下格式定义全局变量define函数: define(id, dependencies, factory)
第一个参数:id是字符串类型,指示模块标识符,这是一个可选参数。如果省略此参数,则模块标识符默认为加载程序中请求的文件的URL作为模块标识符。如果您需要填写此ID,最好是加载程序中模块的URL(填写ID通常是合并多个模块以减少网站中的HTTP请求)。
第二个参数:dependencies是一个数组,它是一个可选参数,用于存储当前模块所依赖的其他模块标识符。
The third parameter: factory is a function or object
Case: Creating a module
define('./bsSave', ['./ajax', './lib/domApi'], function (ajax, domApi){
var remArr = [];
/ / Module code
return remArr;
})
/ / No dependent module can be directly defined using object literals
define({
add: function (x, y){return x + y;},
age: 25,
name: 'luke'
})
CMD模块规范:在CMD中,模块是文件。全局函数定义用于定义模块。格式为:define(id,依靠,工厂);
第一个参数:id是字符串类型,指示模块标识符,这是一个可选参数。如果省略此参数,则模块标识符默认为加载程序中请求的文件的URL作为模块标识符。如果您需要填写此ID,最好是加载程序中模块的URL(填写ID通常是合并多个模块以减少网站中的HTTP请求)。
第二个参数:dependencies是一个数组,它是一个可选参数,用于存储当前模块所依赖的其他模块标识符。
第三个参数:factory可以是函数,也可以是对象或字符串。当工厂是对象或字符串时,表示模块的接口是对象或字符串。
案例:定义模块
define('./BsSave', ['./ajax'], function (require, exports, module){
var BsSave = {};
/ / Module code
return BsSave;
})
/ / Define the JSON data module
define({"name": "csh"})
/ / Define the template module by string
define('this is {{data}}');
//factory is a function, which means the constructor of the module. The data of the module can be output by return.
define(function (){
var modArr = [];
/ / Module code
Return modArr; / / output the data of the module
})
当模块的第三个参数是一个函数时,该函数还具有三个参数,即require,exports,module
Require:是一种接受模块标识符作为引入其他模块的唯一参数的方法。require方法是同步执行的。异步加载模块可以使用require.async方法。您可以使用require.resolve方法返回模块路径。
案例:加载模块
define(function(require, exports, module){
/ / Synchronous loading module
var ajax = require('./ajax');
/ / Asynchronous loading module
require.async('./ajax', function (ajax){
ajax.get();
})
/ / Return the path of the module, but it will not load the module
require.resolve('./ajax');
})
Exports: used to provide module interfaces to the outside, of course, it is also possible to use return directly.
Case: Provide an interface to the module
define(function(require, exports, module){
Exports.name = 'csh'; //Outbound attributes
Exports.do = function (){}; //Outer methods
/ / This can also provide an interface to the outside
return {
name: 'csh',
do: function (){}
}
/ / This can also provide an interface to the outside
module.exports = {
name: 'csh',
do: function (){}
}
//Note that the following is wrong
exports = {
name: 'csh',
do: function (){}
}
})
模块:
是一个对象,用于存储与当前模块关联的某些属性和方法。
module.id:是模块的唯一标识符。
Module.uri:根据模块系统的路径解析规则,获取模块的绝对路径。
Module.dependencies:指示模块的依赖关系。
Module.exports:当前模块提供的接口。
以下是AMD和CMD之间差异的解释(详细差异可以在上面进行比较):
AMD是RequireJS在升级过程中定义的模块定义的标准化输出。
CMD是SeaJS在升级过程中模块定义的标准输出。
同样,CommonJS Modules / 2.0规范是BravoJS在升级过程中定义模块定义的标准。
这些规范的目的是用于JavaScript的模块化开发,尤其是在浏览器端。
目前,这些规范的实现可以达到浏览器模块化开发的目的。