其它模块化方案

CommonJS中require的功能是加载并执行一个js文件,并返回该文件的exports对象,是同步的。由于在服务器端加载并执行一个文件的时间是可以忽略的,所以可以在运行时加载,是同步的。但是在浏览器端,如果每加载一个文件都要发请求,在网速慢的情况下得移植等请求返回,浏览器就会卡死,阻塞后面代码的运行。
为了解决这个问题,后面发展起来了众多的前端模块化规范,包括 CommonJS 大致有如下几种:

image.png

AMD (Asynchronous Module Definition)

RequireJS 是一个 js 文件和模块加载器。它非常适合在浏览器中使用,但它也可以用在其他 js 环境, 就像 Rhino 和 Node。 使用 RequireJS 加载模块化脚本能提高代码的加载速度和质量。
它解决了 CommonJS 规范不能用于浏览器端的问题,而 AMD 就是 RequireJS 在推广过程中对模块定义的规范化产出。
来看看 AMD 规范的实现:

<script src="require.js"></script>
<script src="a.js"></script>

首先要在 html 文件中引入 require.js 工具库,就是这个库提供了定义模块、加载模块等功能。它提供了一个全局的 define 函数用来定义模块。所以在引入 require.js 文件后,再引入的其它文件,都可以使用 define 来定义模块。

define(id?, dependencies?, factory)

id 可选参数,模块标识。没有就使用js文件名。如果一个 js 文件只定义了一个模块时,这个参数是可以省略的;
dependencies 可选参数,模块的所有依赖。没有可以不写;
factory 工厂函数,如果是函数只调用一次,返回模块要导出的值。如果是对象则为模块导出的值。

所以模块A可以这么定义

// a.js
define(function(){
    var name = 'morrain'
    var age = 18
    return {
        name,
        getAge: () => age
    }
})
// b.js
define(['a.js'], function(a){
    var name = 'lilei'
    var age = 15
    console.log(a.name) // 'morrain'
    console.log(a.getAge()) // 18
    return {
        name,
        getAge: () => age
    }
})

它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在回调函数中,等到加载完成之后,这个回调函数才会运行。

RequireJS 的基本思想是,通过 define 方法,将代码定义为模块。当这个模块被 require 时,它开始加载它依赖的模块,当所有依赖的模块加载完成后,开始执行回调函数,返回值是该模块导出的值。

CMD (Common Module Definition)

和 AMD 类似,CMD 是 Sea.js 在推广过程中对模块定义的规范化产出。Sea.js 是阿里的玉伯写的。它的诞生在 RequireJS 之后,玉伯觉得 AMD 规范是异步的,模块的组织形式不够自然和直观。于是他在追求能像 CommonJS 那样的书写形式。于是就有了 CMD 。
来看看 CMD 规范的实现:

<script src="sea.js"></script>
<script src="a.js"></script>

首先要在 html 文件中引入 sea.js 工具库,就是这个库提供了定义模块、加载模块等功能。它提供了一个全局的 define 函数用来定义模块。所以在引入 sea.js 文件后,再引入的其它文件,都可以使用 define 来定义模块。

// 所有模块都通过 define 来定义
define(function(require, exports, module) {

  // 通过 require 引入依赖
  var a = require('xxx')
  var b = require('yyy')

  // 通过 exports 对外提供接口
  exports.doSomething = ...

  // 或者通过 module.exports 提供整个接口
  module.exports = ...

})
// a.js
define(function(require, exports, module){
    var name = 'morrain'
    var age = 18

    exports.name = name
    exports.getAge = () => age
})
// b.js
define(function(require, exports, module){
    var name = 'lilei'
    var age = 15
    var a = require('a.js')

    console.log(a.name) // 'morrain'
    console.log(a.getAge()) //18

    exports.name = name
    exports.getAge = () => age
})

Sea.js 可以像 CommonsJS 那样同步的形式书写模块代码的秘诀在于: 当 b.js 模块被 require 时,b.js 加载后,Sea.js 会扫描 b.js 的代码,找到 require 这个关键字,提取所有的依赖项,然后加载,等到依赖的所有模块加载完成后,执行回调函数,此时再执行到 require('a.js') 这行代码时,a.js 已经加载好在内存中了.

ES6 Module

前面提到的 CommonJS 是服务于服务端的,而 AMD、CMD 是服务于浏览器端的,但它们都有一个共同点:都在代码运行后才能确定导出的内容
从 ES6 开始,在语言标准的层面上,实现了模块化功能,而且实现得相当简单,完全可以取代 CommonJS 和 CMD、AMD 规范,成为浏览器和服务器通用的模块解决方案。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容