资讯专栏INFORMATION COLUMN

ES6 系列之模块加载方案

pinecone / 1652人阅读

摘要:感谢感谢和在推动模块化发展方面做出的贡献。与引用阮一峰老师的标准参考教程规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。规定了新的模块加载方案。与引用阮一峰老师的入门它们有两个重大差异。

前言

本篇我们重点介绍以下四种模块加载规范:

AMD

CMD

CommonJS

ES6 模块

最后再延伸讲下 Babel 的编译和 webpack 的打包原理。

require.js

在了解 AMD 规范之前,我们先来看看 require.js 的使用方式。

项目目录为:

* project/
    * index.html
    * vender/
        * main.js
        * require.js
        * add.js
        * square.js
        * multiply.js

index.html 的内容如下:



    
        require.js
    
    
        

Content

data-main="vender/main" 表示主模块是 vender 下的 main.js

main.js 的配置如下:

// main.js
require(["./add", "./square"], function(addModule, squareModule) {
    console.log(addModule.add(1, 1))
    console.log(squareModule.square(3))
});

require 的第一个参数表示依赖的模块的路径,第二个参数表示此模块的内容。

由此可以看出,主模块依赖 add 模块square 模块

我们看下 add 模块add.js 的内容:

// add.js
define(function() {
    console.log("加载了 add 模块");
    var add = function(x, y) { 
        return x + y;
    };

    return {      
        add: add
    };
});

requirejs 为全局添加了 define 函数,你只要按照这种约定的方式书写这个模块即可。

那如果依赖的模块又依赖了其他模块呢?

我们来看看主模块依赖的 square 模块square 模块的作用是求出一个数字的平方,比如输入 3 就返回 9,该模块依赖一个乘法模块,该乘法模块即 multiply.js 的代码如下:

// multiply.js
define(function() {
    console.log("加载了 multiply 模块")
    var multiply = function(x, y) { 
        return x * y;
    };

    return {      
        multiply: multiply
    };
});

square 模块就要用到 multiply 模块,其实写法跟 main.js 添加依赖模块一样:

// square.js
define(["./multiply"], function(multiplyModule) {
    console.log("加载了 square 模块")
    return {      
        square: function(num) {
            return multiplyModule.multiply(num, num)
        }
    };
});

require.js 会自动分析依赖关系,将需要加载的模块正确加载。

requirejs 项目 Demo 地址:https://github.com/mqyqingfeng/Blog/tree/master/demos/ES6/module/requirejs

而如果我们在浏览器中打开 index.html,打印的顺序为:

加载了 add 模块
加载了 multiply 模块
加载了 square 模块
2
9
AMD

在上节,我们说了这样一句话:

requirejs 为全局添加了 define 函数,你只要按照这种约定的方式书写这个模块即可。

那这个约定的书写方式是指什么呢?

指的便是 The Asynchronous Module Definition (AMD) 规范。

所以其实 AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。

你去看 AMD 规范) 的内容,其主要内容就是定义了 define 函数该如何书写,只要你按照这个规范书写模块和依赖,require.js 就能正确的进行解析。

sea.js

在国内,经常与 AMD 被一起提起的还有 CMD,CMD 又是什么呢?我们从 sea.js 的使用开始说起。

文件目录与 requirejs 项目目录相同:

* project/
    * index.html
    * vender/
        * main.js
        * require.js
        * add.js
        * square.js
        * multiply.js

index.html 的内容如下:




    sea.js


    

Content

main.js 的内容如下:

// main.js
define(function(require, exports, module) {
    var addModule = require("./add");
    console.log(addModule.add(1, 1))

    var squareModule = require("./square");
    console.log(squareModule.square(3))
});

add.js 的内容如下:

// add.js
define(function(require, exports, module) {
    console.log("加载了 add 模块")
    var add = function(x, y) { 
        return x + y;
    };
    module.exports = {      
        add: add
    };
});

square.js 的内容如下:

define(function(require, exports, module) {
    console.log("加载了 square 模块")
    var multiplyModule = require("./multiply");
    module.exports = {      
        square: function(num) {
            return multiplyModule.multiply(num, num)
        }
    };

});

multiply.js 的内容如下:

define(function(require, exports, module) {
    console.log("加载了 multiply 模块")
    var multiply = function(x, y) { 
        return x * y;
    };
    module.exports = {      
        multiply: multiply
    };
});

跟第一个例子是同样的依赖结构,即 main 依赖 add 和 square,square 又依赖 multiply。

seajs 项目 Demo 地址:https://github.com/mqyqingfeng/Blog/tree/master/demos/ES6/module/seajs

而如果我们在浏览器中打开 index.html,打印的顺序为:

加载了 add 模块
2
加载了 square 模块
加载了 multiply 模块
9
CMD

与 AMD 一样,CMD 其实就是 SeaJS 在推广过程中对模块定义的规范化产出。

你去看 CMD 规范的内容,主要内容就是描述该如何定义模块,如何引入模块,如何导出模块,只要你按照这个规范书写代码,sea.js 就能正确的进行解析。

AMD 与 CMD 的区别

从 sea.js 和 require.js 的例子可以看出:

1.CMD 推崇依赖就近,AMD 推崇依赖前置。看两个项目中的 main.js:

// require.js 例子中的 main.js
// 依赖必须一开始就写好
require(["./add", "./square"], function(addModule, squareModule) {
    console.log(addModule.add(1, 1))
    console.log(squareModule.square(3))
});
// sea.js 例子中的 main.js
define(function(require, exports, module) {
    var addModule = require("./add");
    console.log(addModule.add(1, 1))

    // 依赖可以就近书写
    var squareModule = require("./square");
    console.log(squareModule.square(3))
});

2.对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。看两个项目中的打印顺序:

// require.js
加载了 add 模块
加载了 multiply 模块
加载了 square 模块
2
9
// sea.js
加载了 add 模块
2
加载了 square 模块
加载了 multiply 模块
9

AMD 是将需要使用的模块先加载完再执行代码,而 CMD 是在 require 的时候才去加载模块文件,加载完再接着执行。

感谢

感谢 require.js 和 sea.js 在推动 JavaScript 模块化发展方面做出的贡献。

CommonJS

AMD 和 CMD 都是用于浏览器端的模块规范,而在服务器端比如 node,采用的则是 CommonJS 规范。

导出模块的方式:

var add = function(x, y) { 
    return x + y;
};

module.exports.add = add;

引入模块的方式:

var add = require("./add.js");
console.log(add.add(1, 1));

我们将之前的例子改成 CommonJS 规范:

// main.js
var add = require("./add.js");
console.log(add.add(1, 1))

var square = require("./square.js");
console.log(square.square(3));
// add.js
console.log("加载了 add 模块")

var add = function(x, y) { 
    return x + y;
};

module.exports.add = add;
// multiply.js
console.log("加载了 multiply 模块")

var multiply = function(x, y) { 
    return x * y;
};

module.exports.multiply = multiply;
// square.js
console.log("加载了 square 模块")

var multiply = require("./multiply.js");

var square = function(num) { 
    return multiply.multiply(num, num);
};

module.exports.square = square;

CommonJS 项目 Demo 地址:https://github.com/mqyqingfeng/Blog/tree/master/demos/ES6/module/commonJS

如果我们执行 node main.js,打印的顺序为:

加载了 add 模块
2
加载了 square 模块
加载了 multiply 模块
9

跟 sea.js 的执行结果一致,也是在 require 的时候才去加载模块文件,加载完再接着执行。

CommonJS 与 AMD

引用阮一峰老师的《JavaScript 标准参考教程(alpha)》:

CommonJS 规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。

AMD规范则是非同步加载模块,允许指定回调函数。

由于 Node.js 主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以 CommonJS 规范比较适用。

但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用 AMD 规范。

ES6

ECMAScript2015 规定了新的模块加载方案。

导出模块的方式:

var firstName = "Michael";
var lastName = "Jackson";
var year = 1958;

export {firstName, lastName, year};

引入模块的方式:

import {firstName, lastName, year} from "./profile";

我们再将上面的例子改成 ES6 规范:

目录结构与 requirejs 和 seajs 目录结构一致。



    
        ES6
    
    
        

Content

注意!浏览器加载 ES6 模块,也使用

阅读需要支付1元查看
<