CommonJS、AMD 和 RequireJS 之间的关系?

IT技术 javascript module requirejs amd commonjs
2021-01-19 18:00:50

即使在阅读了很多之后我仍然对CommonJS、AMDRequireJS感到非常困惑

我知道CommonJS(以前称为ServerJS)是在浏览器之外使用该语言时定义一些JavaScript规范(即module)的组CommonJSmodule规范有一些实现,比如Node.jsRingoJS,对吧?

CommonJS异步module定义(AMD) 和RequireJS之间的关系是什么

RequireJS的的实现CommonJS的module定义?如果是,那么AMD是什么

6个回答

RequireJS实现了AMD API (源代码)

CommonJS是一种借助exports对象定义module的方法,该对象定义了module内容。简单地说,一个 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变量来导出module内容和一个module标识符(它描述了与这个module相关的问题module的位置),用于要求依赖项()。CommonJS 有各种实现,包括您提到的Node.js

CommonJS 并不是专门为浏览器设计的,所以它不太适合浏览器环境(*我真的没有这方面的来源——它只是在任何地方都这么说,包括RequireJS 站点。*)显然,这有与异步加载等有关。

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

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

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

  • AMD更适合浏览器,因为它支持module依赖的异步加载。
  • RequireJSAMD 的一个实现,同时也力图保持CommonJS的精神(主要体现在module标识符上)。

更让您困惑的是,RequireJS 虽然是 AMD 实现,但提供了一个 CommonJS 包装器,因此几乎可以直接导入 CommonJS module以与 RequireJS 一起使用。

define(function(require, exports, module) {
  var someModule = require('someModule'); // in the vein of node    
  exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };
});
仅供参考Browserify现在可以让您在浏览器中使用 CommonJS。
2021-03-15 18:00:50
@aaaaaa 您可能希望根据用户请求启用某些功能;所以 AMD 的异步特性可能会派上用场。
2021-03-19 18:00:50
@Eruant 但是,它仍然没有 AMD 那样的异步性质。
2021-03-26 18:00:50
查看弥合两种格式差距的uRequire.org项目 - 写入其中一个(或两者),部署到这两种格式中的任何一种或简单的 <script>
2021-04-01 18:00:50
RequireJS 文档中提到的 CommonJS 不适合浏览器的原因 - “CommonJS require() 是一个同步调用,预计会立即返回module。这在浏览器中效果不佳”更多信息在这里
2021-04-03 18:00:50

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

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

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

谢谢你的回答。现在module在 ES2015 的 JS 中是官方的,这是否意味着它们比 AMD 或普通 JS 更受欢迎?
2021-03-12 18:00:50
这不是异步加载module的意思。您可能在谈论动态/延迟加载。使用异步,您建议加载一个文件,然后一段时间后它会在加载完成后回调。使用同步,您建议加载一个文件,然后整个线程阻塞,直到该文件完成加载;在文件加载之前不会执行进一步的代码。前者可以以不可预测性为代价产生更好的性能,而后者每次都可以产生相同的结果,因此更具可预测性。请注意,可以使用各种优化来减轻这些怪癖。
2021-03-20 18:00:50
为什么 CommonJS 主页如此可怕......我只是想查看官方规范。它有语法错误、不完整的文档和维基页面无法解析。
2021-03-21 18:00:50
这并不意味着他们是首选。这完全取决于开发人员的需求。我不认为别无选择并使用 ES6 module是特别好的主意。但是,使用良好的 UMD,您可以解决该问题。加载与 AMD 同步的 CommonJS 包通常是一个好(最好)的想法(为了提高性能)。如果你觉得你应该有更多的控制权,显然。你应该。
2021-03-21 18:00:50

简短的回答是:

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

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
    }
});

该module可以在其他地方用于:

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

一些背景:

实际上,CommonJS不仅仅是一个 API 声明,它只是其中的一部分。AMD 开始时是 CommonJS 列表中module格式的草案规范,但没有达成完全共识,格式的进一步开发转移到了amdjs 组关于哪种格式更好的争论表明 CommonJS 试图涵盖更广泛的问题,并且鉴于其同步性质,它更适合服务器端开发,而 AMD 更适合客户端(浏览器)开发,因为其异步性质和事实上,它源于 Dojo 的module声明实现。

资料来源:

我总是喜欢阅读一些关于为什么事情会这样的历史!感谢您提供这样的背景!
2021-03-14 18:00:50
@RullDawg 不,此处未定义“package/lib”,它是此处使用的第 3 方依赖项
2021-03-16 18:00:50
看代码而不是描述有帮助!:)AMD compliant实际上是RequireJS,对吧?
2021-04-05 18:00:50
我是不是遗漏了什么,还是有什么东西打错了?您定义了“package/lib”,但随后需要“package/myModule”。
2021-04-05 18:00:50

引用

超微

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

通用JS

  • 一种服务器优先的方法
  • 假设同步行为
  • 涵盖更广泛的关注点,例如 I/O、文件系统、Promise等。
  • 支持解包module,感觉更接近ES.next/Harmony规范,让您摆脱AMD强制执行的 define() 包装器
  • 只支持对象作为module。

将 JavaScript 程序module化组织成多个文件并child-modulesmain js module.

问题是 JavaScript 不提供这个。即使在今天最新的 Chrome 和 FF 浏览器版本中也没有。

但是,JavaScript 中是否有任何关键字可以调用另一个 JavaScript module?

这个问题对很多人来说可能是世界彻底崩溃,因为答案是否定的


在 ES5(2009 年发布)中,JavaScript 没有像importincluderequire这样的关键字

ES6 挽救了这一天(2015 年发布)提出了import关键字( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/import),现在所有现代浏览器都支持这一点。

如果您使用 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意味着module将从 Node.js 加载。Node.js 将处理从系统级文件读取到将函数包装到module中的所有事情。

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

我对 CommonJS 和 AMD 很困惑?

CommonJS 和 AMD 只是两种不同的技术,它们如何克服 JavaScript“缺陷”以智能加载module。