CommonJS,AMD 和 RequireJS 之间的关系?

我对 CommonJS,AMD 和 RequireJS 仍然很困惑。即使阅读了很多。

我知道 CommonJS(以前称为 ServerJS)是用于在浏览器之外使用该语言时定义一些 JavaScript 规范(即模块)的组。 CommonJS 模块规范具有某些实现,例如 Node.js 或 RingoJS,对吗?

CommonJS,异步模块定义(AMD)和 RequireJS 之间有什么关系? RequireJS 是 CommonJS 模块定义的实现吗?如果是,那么 AMD 是什么?

答案

RequireJS实现AMD API (源代码)

CommonJS是在exports对象的帮助下定义模块的方法,该对象定义了模块的内容。简而言之,CommonJS 实现可能如下所示:

// someModule.js
exports.doSomething = function() { return "foo"; };

//otherModule.js
var someModule = require('someModule'); // in the vein of node    
exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };

基本上,CommonJS 指定您需要有一个require()函数来获取依赖项,一个exports变量以导出模块内容以及一个用来标识要求的模块标识符(描述了该模块相对于该模块的位置)依赖项( )。 CommonJS 具有各种实现,包括您提到的Node.js。

CommonJS 并不是专门为浏览器而设计的,因此它不太适合浏览器环境( 我确实没有相关资料 - 它在包括RequireJS 网站在内所有地方都这么说 )显然,这有一些不足之处异步加载等

另一方面,RequireJS 实现了 AMD,旨在适应浏览器环境( )。显然,AMD 最初是从 CommonJS Transport 格式衍生出来的,后来演变为自己的模块定义 API。因此,两者之间的相似之处。 AMD 中的新功能是define()函数,该函数允许模块在加载之前声明其依赖性。例如,定义可以是:

define('module/id/string', ['module', 'dependency', 'array'], 
function(module, factory function) {
  return ModuleContents;  
});

因此,CommonJS 和 AMD 是JavaScript模块定义 API,它们具有不同的实现,但是它们来自相同的来源。

  • AMD更适合浏览器,因为它支持异步加载模块依赖项。
  • RequireJSAMD的实现,同时尝试保持CommonJS的精神(主要在模块标识符中)。

更令人困惑的是,RequireJS 作为 AMD 实现,提供了 CommonJS 包装器,因此 CommonJS 模块几乎可以直接导入以与 RequireJS 一起使用。

define(function(require, exports, module) {
  var someModule = require('someModule'); // in the vein of node    
  exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };
});

我希望这有助于澄清问题!

CommonJS不仅限于此 - 它是一个为 JavaScript 定义通用 API 和生态系统的项目。 CommonJS 的一部分是模块规范。 Node.js 和 RingoJS 是服务器端 JavaScript 运行时,是的,它们都基于 CommonJS Module 规范实现模块。

AMD (异步模块定义)是另一种模块规范。 RequireJS可能是 AMD 最受欢迎的实现。与 CommonJS 的主要区别在于 AMD 指定异步加载模块 - 这意味着模块是并行加载的,而不是通过等待加载完成来阻止执行。

因此,AMD 通常更多地用于客户端(浏览器)JavaScript 开发中,而 CommonJS 模块通常用于服务器端。但是,您可以在任何一种环境中使用任何一种模块规范 - 例如,RequireJS 提供了在 Node.js 中运行的说明,browserify是可以在浏览器中运行的 CommonJS Module 实现。

简短的答案是:

CommonJSAMD是有关如何在 javascript 应用程序中声明模块及其依赖项的规范(或格式)。

RequireJS是一个与 AMD 兼容的脚本加载器库,另一个示例是curljs

符合 CommonJS:

摘自Addy Osmani 的书

// package/lib is a dependency we require
var lib = require( "package/lib" );

// behavior for our module
function foo(){
    lib.log( "hello world!" );
}

// export (expose) foo to other modules as foobar
exports.foobar = foo;

符合 AMD 标准:

// package/lib is a dependency we require
define(["package/lib"], function (lib) {

    // behavior for our module
    function foo() {
        lib.log( "hello world!" );
    }

    // export (expose) foo to other modules as foobar
    return {
        foobar: foo
    }
});

该模块可以在其他地方使用:

require(["package/myModule"], function(myModule) {
    myModule.foobar();
});

一些背景:

实际上, CommonJS不仅仅是一个 API 声明,而且其中只有一部分处理该声明。 AMD 最初是 CommonJS 列表中模块格式的规范草案,但尚未达成完全共识,因此该格式的进一步开发移交给了amdjs 组 。关于哪种格式更好的争论指出,CommonJS 试图涵盖更广泛的关注点,并且鉴于其同步特性,它更适合于服务器端开发,而鉴于其异步特性和特性,AMD 更适合于客户端(浏览器)开发。它起源于 Dojo 的模块声明实现的事实。

资料来源:

报价单

AMD

  • 一种浏览器优先的方法
  • 选择异步行为并简化向后兼容性
  • 它没有文件 I / O 的任何概念。
  • 它支持对象,函数,构造函数,字符串,JSON 和许多其他类型的模块。

CommonJS

  • 一种服务器优先的方法
  • 假设同步行为
  • 涵盖更广泛的关注点,例如 I / O,文件系统,承诺等。
  • 支持展开的模块,它感觉更接近ES.next/Harmony规范,从而使您摆脱了AMD强制执行的 define()包装器。
  • 仅支持将对象作为模块。

将 JavaScript 程序模块化组织成几个文件,并从main js module调用child-modules是很正常的。

问题是 JavaScript 不提供此功能。直到今天,最新版的 Chrome 和 FF 浏览器都没有。

但是,JavaScript 中是否有关键字可以调用另一个 JavaScript 模块?

这个问题可能是世界上的许多完全崩溃,因为答案是没有


在 ES5(于 2009 年发布)中,JavaScript 没有诸如importincluderequire 之类的关键字。

ES6 节省了建议import关键字( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/import )的日期(2015 年发布),但是没有浏览器实现此目的。

如果您使用 Babel 6.18.0 并仅通过 ES2015 选项进行转换

import myDefault from "my-module";

您将再次获得require

"use strict";
var _myModule = require("my-module");
var _myModule2 = _interopRequireDefault(_myModule);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

这是因为require意味着将从 Node.js 加载模块。 Node.js 将处理从系统级文件读取到将函数包装到模块中的所有内容。

因为在 JavaScript 中,函数是表示模块的唯一包装。

我对 CommonJS 和 AMD 感到困惑?

CommonJS 和 AMD 都是仅两种不同的技术,可以克服 JavaScript 的 “缺陷” 以智能地加载模块。