【问题标题】:Relation between CommonJS, AMD and RequireJS?CommonJS、AMD 和 RequireJS 之间的关系?
【发布时间】:2017-08-26 04:01:45
【问题描述】:

我对 CommonJS、AMDRequireJS 仍然很困惑,即使阅读了很多。

我知道CommonJS(以前的ServerJS)是一个组,用于定义一些JavaScript规范(即模块),当语言在外面使用时浏览器。 CommonJS 模块规范有一些实现,例如 Node.jsRingoJS,对吧?

CommonJS异步模块定义(AMD)和RequireJS有什么关系?

RequireJSCommonJS 模块定义的实现吗?如果是,那么 AMD 是什么?

【问题讨论】:

  • 阅读requirejs.org/docs/whyamd.html 会澄清很多,因为它提到了所有这些。 (将其作为评论发布,因为我不认为这是一个完整的答案)。
  • 我可以问或补充更多吗? ES2015 import 语句如何或在哪里适合所有这些;例如从 'ember' 导入 Ember;
  • 还有一个 systemjs 可以加载任何支持的 JS 模块格式,例如(CommonJS、UMD、AMD、ES6)。

标签: javascript module requirejs amd commonjs


【解决方案1】:

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 传输格式衍生出来的,并演变成自己的模块定义 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"; };
});

【讨论】:

  • 查看uRequire.org 项目,它弥补了两种格式的差距 - 写入其中一种(或两种格式),部署到两种格式中的任何一种或简单的
  • 仅供参考 Browserify 现在允许您在浏览器中使用 CommonJS。
  • @Eruant 但是,它仍然没有 AMD 那样的异步特性。
  • RequireJS 文档中提到 CommonJS 不适合浏览器的原因 - "CommonJS require() 是一个同步调用,预计会立即返回模块。这确实在浏览器中无法正常工作”。更多信息here.
  • @aaaaaa 您可能希望根据用户请求启用某些功能;所以 AMD 的异步特性可能会派上用场。
【解决方案2】:

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 模块实现。

【讨论】:

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

简短的回答是:

CommonJSAMD 是关于如何在 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 的模块声明实现。

来源:

【讨论】:

  • 查看代码而不是描述会有所帮助! :) AMD compliant 实际上是 RequireJS,对吧?
  • 是我遗漏了什么,还是输入错误?您定义了“package/lib”,但随后需要“package/myModule”。
  • 我总是喜欢阅读一些关于为什么事情会这样的历史!感谢您提供背景!
  • @RullDawg 不,这里没有定义“package/lib”,它是一个第 3 方依赖在这里使用
【解决方案4】:

Quoting

AMD

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

CommonJS

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

【讨论】:

    【解决方案5】:

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

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

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

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


    在 ES5(2009 年发布)中,JavaScript 没有 importincluderequire 等关键字。

    ES6 拯救了一天(2015 年发布)提出 import 关键字(https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/import),现在所有modern browsers supportthis。

    如果您使用 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“缺陷”以智能加载模块的两种不同技术。

    【讨论】:

      【解决方案6】:

      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。

      资源:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-20
        • 2012-08-10
        • 2014-01-14
        • 1970-01-01
        相关资源
        最近更新 更多