AMD和CMD是ES6前浏览器模块化方案,核心区别在于执行时机:AMD依赖前置、加载完才执行工厂函数,CMD工厂函数立即执行、require时才加载依赖。
AMD 和 CMD 都是浏览器端为解决脚本依赖与加载顺序问题而诞生的异步模块规范,但它们的设计哲学和执行时机截然不同——不是“谁更好”,而是“谁更适合你的构建链路”。
在 ES

import/export 成为主流前,浏览器没有原生模块系统。多个 标签手动加载易出错:ReferenceError)AMD)和 SeaJS(推 CMD)分别提出标准化方案,目标一致:让模块可声明依赖、可隔离、可异步加载。
define() 的参数写法暴露核心分歧两者都用全局 define() 定义模块,但参数结构直接体现理念差异:
AMD(RequireJS):依赖数组前置,强制“声明即加载”define(['./utils', './api'], function(utils, api) {
// 所有依赖已加载完毕,立即执行
return { init: () => utils.log(api.getData()) };
});CMD(SeaJS):依赖在函数体内按需 require(),延迟执行define(function(require, exports, module) {
// 此时 utils.js 还没加载
var utils = require('./utils'); // 真到这行才发起请求
var api = require('./api');
exports.init = function() {
utils.log(api.getData());
};
});关键区别不在“是否异步”(二者都是异步加载),而在模块工厂函数何时执行:
– AMD:依赖全部 ready 后才调用 factory,适合“启动即全量加载”的场景
– CMD:factory 立即执行,require() 调用时才触发加载,适合“点击才加载某功能”的懒加载逻辑
现代前端工程几乎不再手写 define(),原因很实在:
ESM 为输入,自动转译并内联依赖,无需手动 require([]) 或 define()
CommonJS(Node.js 风格)仍常见于服务端或构建脚本,但浏览器运行时需打包转换require.config() 路径别配错(尤其 baseUrl 和 paths)CMD 中 require() 必须写在 factory 函数内,写在外面会报 require is not defined
如果你被迫维护一个老 AMD/CMD 项目,这几个点常导致白屏或静默失败:
define() 写成箭头函数 → this 绑定失效,require 拿不到上下文module.exports → RequireJS 不识别,返回 undefined
exports 和 module.exports 同时赋值 → SeaJS 以 module.exports 为准,前者被忽略require.config() 里注册,却写了 require('jquery') → 报 404,而不是提示“未配置 alias”历史价值在于理解模块演进逻辑;工程实践上,ESM + 构建工具才是今天该投入精力的地方。那些 define([...]) 和 require(['x'], ...),现在更多是调试时需要读懂的“古代码”。