欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

CommonJS,AMD模块化规范

程序员文章站 2022-06-13 22:14:36
...

模块化开发依然成为前端开发的主流,我们需要做的就是将不同的模块组织起来。最有名的前端模块管理器即requireJS,采用AMD标准。除此之外的其他模块管理器各有特色。

模块化规范

CommonJS

CommonJS**用在服务器端,是服务器模块化的一种规范,NodeJS是其具体实现。加载模块是同步**的。由于NodeJS主要用于服务器的编程,加载的模块文件一般已经存在本地,所以加载起来很快,不用考虑异步加载问题,而前端浏览器需要从服务器加载模块,则必须异步加载,就需要AMD,CDM。
根据CommonJS规范,一个单独文件就是一个模块,加载模块使用require()方法,该方法读取一个文件并执行,最后返回exports对象。
CommonJS定义的模块分为:{模块引用(require)} {模块定义(exports)} {模块标识(module)}

  • require()用来引入外部模块;
  • exports对象用于导出当前模块的方法或变量,唯一的导出口;
  • module对象就代表模块本身,存储了模块的元信息。具体如下:
    • module.id——模块的ID。
    • module.dependencies——一个数组,存储了此模块依赖的所有模块的ID列表。
    • module.exports——与exports指向同一个对象。

AMD/CMD

用在浏览器端,异步加载
AMD:异步模块定义,是RequireJS在推广过程中对模块定义的规范化产出。先提出的
CMD:通用模块定义,是SeaJS (由玉伯-淘宝前端工程师提出)在推广过程中对模块定义的规范化产出
区别:
1. 对于依赖的模块AMD是提前执行,CMD是延迟执行。不过RequireJS从2.0开始,也改成可以延迟执行(根据写法不同,处理方式不通过)。
2. CMD推崇依赖就近,AMD推崇依赖前置。即SeaJS是懒执行,requireJS是预执行。
- SeaJS只会在真正需要时才执行该模块,严格按照代码中require模块的顺序执行。
- RequireJS中所有依赖的模块加载被提前并行执行了,执行的顺序不能保证。这个问题使用shim参数就可以解决了,shim里面配置好依赖。

官方的解释:SeaJS与RequireJS 的异同

//AMD 
define(['./a','./b'], function (a, b) { 

    //依赖一开始就写好 
    a.test(); 
    b.test(); 
}); 

//CMD 
define(function (requie, exports, module) { 

    //依赖可以就近书写 
    var a = require('./a'); 
    a.test(); 

    ... 
    //软依赖 
    if (status) { 

        var b = requie('./b'); 
        b.test(); 
    } 
}); 

SeaJS和 RequireJS中的define

define(id?, deps?, factory);

事实上SeaJS和RequireJS的define前两个参数的确一样。id都为字符串,都遵循 Module Identifiers。deps都是指依赖模块,类型都为数组。区别仅在于第三个参数factory,虽然类型也都是函数,但factory的参数意义却不同。
RequireJS中factory的参数有两种情况:
1. factory实参和deps数组元素一一对应,数组元素有几个,factory实参个数就有几个。

define(['a', 'b'], function(a, b){
        // todo
});

2. 固定为require,exports, module(modules/wrappings格式)。

define(function(require, exports, module){
    // todo
});

这种方式是RequireJS后期向 Modules/Wrappings 的妥协,即兼容了它。而SeaJS的define仅支持RequireJS的第二种写法:Modules/Wrappings。

SeaJS和 RequireJS中的require

SeaJS中“依赖”都需要使用require函数去获取,虽然SeaJS的define的第二个参数deps也有“依赖”的意思,但它是提供打包工具(SPM)用的。此外,SeaJS的require是作为参数传入匿名函数内的,RequireJS的require则是全局变量。

三种编写模块的模式

    define(function(require, exports, module) {
    var a = require('a'); //引入a模块
    var b = require('b'); //引入b模块

    var data1 = 1; //私有数据

    var func1 = function() { //私有方法
        return a.run(data1);
    }

    exports.data2 = 2; //公共数据

    exports.func2 = function() { //公共方法
        return 'hello';
    }
});

或者:

    define(function(require) {
    var a = require('a'); //引入a模块
    var b = require('b'); //引入b模块

    var data1 = 1; //私有数据

    var func1 = function() { //私有方法
        return a.run(data1);
    }

    return {
        data2: 2,
        func2: function() {
            return 'hello';
        }
    };
});

如果模块定义没有其它代码,只返回一个对象,还可以有如下简化写法:

define({
    data: 1,
    func: function() {
        return 'hello';
    }
})

这种写法适合定义纯JSON数据的模块。

模块化管理器

bower

主要用来进行模块的安装,升级和删除

npm install -g bower
bower install jquery
bower update jquery
bower uninstall jquery

具体内容详见bower一文中。

Grunt

前端开发利器,用来打包管理.js
具体详见grunt+bower 一文中。

browserify

Browserify 是目前最常用的 CommonJS 格式转换的工具。本身也是一个NodeJS模块,可以通过npm来安装。使用类似NodeJS的require的方式来组织浏览器的javascript端代码。

npm install -g browserify