Skip to content

模块

js 的三大模块规范

CommonJS、AMD、ES Module

CommonJS 规范

CommonJS 是业界最早正式提术测 JavaScript 模块规范,主要用于服务端,随着 Node.js 越来越普及,这个规范也被业界广泛应用。对于模块规范而言,一般会包含两个方面的内容:

  • 统一的模块化代码规范
  • 实现自动加载模块的加载器(loader
js
// module-a.js
const data = 'hello world'
function getData() {
  return data
}
module.export = { getData }

// index.js
const { getData } = require('./module-a.js')

console.log(getData())

代码中使用 require 来导入一个模块,用 module.export 来导出一个模块。实际上 Node.js 内部会有相应的 loader 转移模块代码,最后模块代码会被处理成下面这样:

js
(function (exports, require, module, __filename, __dirname) {
  // 执行模块代码
  // 返回exports对象
})

对 CommonJS 而言,一方面它定义了一套完整的模块化代码规范,另一方面 Node.js 为之实现了自动加载模块的 loader,看上去是一个不错的模块规范,但也存在一些问题:

  1. 模块加载器由 Node.js 提供,依赖了 Node.js 本身的功能实现,比如文件系统,如果 CommonJS 模块直接放到浏览器中是无法执行的。当然,业界也产生了 browserify 这种打包工具来支持打包 CommonJS 模块,从而顺利在浏览器中执行,相当于社区实现了一个第三方的 loader
  2. CommonJS 本身约定以同步的方式进行模块加载,这种加载机制放在服务端没什么问题,一是模块都在本地,不需要进行网络 IO,二来只有服务启动时才会加载模块,而且服务通常启动后会一直运行,所以对服务的性能没有太大的影响。但如果这种加载机制放到浏览器,会带来明显的性能问题。它会产生大量同步的模块请求,浏览器要等待响应返回后才能继续解析模块。也就是说,模块请求会造成浏览器 JS 解析过程的阻塞,导致页面加载速度缓慢

总之,CommonJS 是一个不太适合在浏览器中运行的模块规范。因此,业界也设计出了全新的规范来作为浏览器端的模块标准,最知名的就是 AMD 了

AMD

AMD 全称为 Asynchronous Module Definition,即一步模块定义规范。模块根据这个规范,在浏览器中会被异步加载,也就不会产生同步请求导致的浏览器解析过程阻塞的问题了。

js
// main.js
define(['./print'], (printModule) => {
  printModule.print('main')
})

// print.js
define(() => {
  return {
    print(msg) {
      console.log(`print${msg}`)
    },
  }
})

ES Module