CommonJS,AMD和RequireJS之间的关系?

gre*_*emo 817 javascript module amd commonjs requirejs

我对CommonJS,AMD和RequireJS仍感到非常困惑.即使阅读了很多.

我知道CommonJS(以前称为ServerJS)是一个用于在浏览器外部使用语言时定义一些JavaScript规范(即模块)的组.CommonJS模块规范有一些像Node.js或RingoJS的实现,对吧?

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

jak*_*kee 754

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"; };
Run Code Online (Sandbox Code Playgroud)

基本上,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;  
});
Run Code Online (Sandbox Code Playgroud)

因此,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"; };
});
Run Code Online (Sandbox Code Playgroud)

我希望这有助于澄清事情!

  • FYI [Browserify](http://browserify.org/)现在允许您在浏览器中使用CommonJS. (50认同)
  • @Eruant但是,它仍然不像AMD那样异步. (9认同)
  • CommonJS不适合在RequireJS docs中提到的浏览器 - *"CommonJS require()是一个同步调用,它应该立即返回模块.这在浏览器"*中不起作用.更多信息[这里](http://requirejs.org/docs/why.html). (8认同)
  • 查看http://uRequire.org项目,它弥补了两种格式的差距 - 写入(或两者),部署到任何两个或简单的<script> (7认同)
  • @aaaaaa您可能希望根据用户请求启用某些功能; 所以AMD的异步性可能会派上用场. (4认同)
  • @deeperx - 这是不相关的,因为它连接文件所以服务器只需要服务一个? (2认同)
  • @jayarjo:不,我不能. (2认同)

Nat*_*ate 196

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

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

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

  • 为什么CommonJS主页如此可怕......我只是想查看官方规范.它有语法错误,文档不完整,维基页面无法解析. (18认同)
  • 这不是异步加载模块的意思.你可能在谈论动态/延迟加载.使用async,您建议加载一个文件,然后一段时间后它将在加载完成后回调.使用sync,您建议加载一个文件,然后整个线程阻塞,直到该文件加载完毕; 在文件加载之前不再执行任何代码.前者可以以不可预测性为代价产生更好的性能,而后者每次都可以产生相同的结果,因此更具可预测性.请注意,可以使用各种优化来缓解这些怪癖. (7认同)

mmu*_*lva 185

简短的回答是:

CommonJS AMD是关于如何在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;
Run Code Online (Sandbox Code Playgroud)

符合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
    }
});
Run Code Online (Sandbox Code Playgroud)

在其他地方,该模块可用于:

require(["package/myModule"], function(myModule) {
    myModule.foobar();
});
Run Code Online (Sandbox Code Playgroud)

一些背景:

实际上,CommonJS不仅仅是一个API声明,只有一部分涉及到它.AMD最初是作为CommonJS列表中模块格式的规范草案,但未达成完全共识,格式的进一步发展转移到amdjs组.关于哪种格式更好的说法CommonJS试图涵盖更广泛的关注点,并且鉴于其同步特性,它更适合服务器端开发,并且AMD更适合客户端(浏览器)开发,因为它具有异步性和事实上,它源于Dojo的模块声明实现.

资料来源:

  • 查看代码而不是描述会有所帮助!:) `AMD 兼容` 实际上是 RequireJS,对吗? (2认同)

zan*_*ngw 26

引用

AMD:

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

CommonJS:

  • 一种服务器优先的方法
  • 假设同步行为
  • 涵盖更广泛的问题,如I/O,文件系统,承诺等.
  • 支持展开的模块,它可以感觉更接近ES.next/Harmony规范,释放你AMD强制执行的define()包装器.
  • 仅支持对象作为模块.


pro*_*sti 17

将JavaScript程序模块化组织成几个文件并从中调用是很正常child-modulesmain js module.

事情是JavaScript没有提供这个.即使在今天的Chrome和FF的最新浏览器版本中也是如此.

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

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


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

ES6保存了当天(2015年发布)提出import关键字( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/import),但没有浏览器实现这一点.

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

import myDefault from "my-module";
Run Code Online (Sandbox Code Playgroud)

你会require再来的.

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

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

因为JavaScript函数是表示模块的唯一包装器.

我对CommonJS和AMD感到很困惑?

CommonJS和AMD都只是两种不同的技术,如何克服JavaScript"缺陷"来加载模块智能.

  • 应该更新你的答案,因为现在所有[现代浏览器都支持](https://caniuse.com/#feat=es6-module-dynamic-import) `import` (3认同)