CommonJS,AMD和RequireJS之间的关系?

时间:2013-05-13 11:56:24

标签: javascript module requirejs amd commonjs

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

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

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

6 个答案:

答案 0 :(得分:735)

RequireJS 实施 AMD API (source)

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变量来导出模块内容和一个模块标识符(它描述了相关模块的位置)到此模块)用于要求依赖项(source)。 CommonJS有各种实现,包括你提到的 Node.js

CommonJS并没有特别考虑到浏览器的设计,因此它不能很好地适应浏览器环境(我真的没有这方面的资源 - 它只是在任何地方都这样说,包括the RequireJS site. )显然,这与异步加载等有关。

另一方面,RequireJS实现了AMD,其设计适合浏览器环境(source)。显然,AMD最初是作为CommonJS Transport格式的衍生产品,并发展成为自己的模块定义API。因此两者之间的相似之处。 AMD中的新功能是define()函数,它允许模块在加载之前声明其依赖项。例如,定义可以是:

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

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

  • AMD 更适合浏览器,因为它支持异步加载模块依赖项。
  • RequireJS AMD 的实现,同时努力保持 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"; };
});

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

答案 1 :(得分:194)

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

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

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

答案 2 :(得分:183)

简短的回答是:

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

RequireJS 是符合AMD标准的脚本加载程序库,curljs是另一个示例。

CommonJS兼容:

取自Addy Osmani's book

// 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 group。关于哪种格式更好的说法CommonJS试图涵盖更广泛的关注点,并且鉴于其同步特性,它更适合服务器端开发,并且AMD更适合客户端(浏览器)开发,因为它具有异步性和事实上,它的根源在于Dojo的模块声明实现。

来源:

答案 3 :(得分:24)

Quoting

<强> AMD

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

<强> CommonJS的

  • 一个服务器优先方法
  • 假设同步行为
  • 涵盖更广泛的问题,例如I / O,文件系统,承诺等。
  • 支持展开的模块,它可以感觉更接近ES.next/Harmony规范,释放<?php class New_menu_model extends CI_Model { function get_domains() { $result = $this->db->get ( 'domenii' ); $menu = array( 'menus' => array(), 'parent_menus' => array() ); foreach($result->result_array() as $row) { //creates entry into menus array with current menu id ie. $menus['menus'][1] $menu['menus'][$row['id_domeniu']] = $row; //creates entry into parent_menus array. parent_menus array contains a list of all menus with children $menu['parent_menus'][$row['parent']][] = $row['id_domeniu']; } return $menu; } function buildMenu($parent, $menu) { $html = ""; if (isset($menu['parent_menus'][$parent])) { $html .= "<ul>"; foreach ($menu['parent_menus'][$parent] as $menu_id) { if (!isset($menu['parent_menus'][$menu_id])) { $html .= "<li><a href='#'>" . $menu['menus'][$menu_id]['nume_domeniu'] . "</a></li>"; } if (isset($menu['parent_menus'][$menu_id])) { $html .= "<li><a href='#'>" . $menu['menus'][$menu_id]['nume_domeniu'] . "</a>"; $html .= $this->buildMenu($menu_id, $menu); $html .= "</li>"; } } $html .= "</ul>"; } return $html; } } ?> 强制执行的define()包装器。
  • 仅支持对象作为模块。

答案 4 :(得分:12)

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

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

  

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

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

在ES5(2009年发布)中,JavaScript没有导入包含需要等关键字。

ES6保存了当天(2015年发布)提议导入关键字(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表示将从Node.js加载模块。 Node.js将处理从系统级文件读取到包装函数到模块的所有内容。

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

  

我对CommonJS和AMD感到很困惑?

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

答案 5 :(得分:2)

AMD

  • 在JavaScript中引入以将JavaScript项目扩展为多个文件
  • 主要用于基于浏览器的应用程序和库
  • 流行的实现是RequireJSDojo Toolkit

CommonJS

  • 这是处理大型项目的大量功能,文件和模块的规范
  • Mozilla于2009年1月推出的初始名称ServerJS
  • 在2009年8月更名为CommonJS,以显示API的更广泛的适用性
  • 最初的实现是服务器,nodejs,基于桌面的库

示例

upper.js文件

exports.uppercase = str => str.toUpperCase()

main.js文件

const uppercaseModule = require('uppercase.js')
uppercaseModule.uppercase('test')

摘要

  • AMD –最古老的模块系统之一,最初由require.js库实现。
  • CommonJS –为Node.js服务器创建的模块系统。
  • UMD –另外一个模块系统,建议作为通用模块系统,与 AMD 和CommonJS兼容。

资源: