AMD,CMD,CommonJS和UMD

2021-03-05  本文已影响0人  魂斗驴

由于项目中引入的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);

通过组合参数,此简单的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的模块化开发,尤其是在浏览器端。

目前,这些规范的实现可以达到浏览器模块化开发的目的。

参考

AMD, CMD, CommonJS and UMD

上一篇 下一篇

猜你喜欢

热点阅读