Отношения между CommonJS, AMD и RequireJS?

840

Я все еще очень запутался в CommonJS, AMD и RequireJS , даже после того, как много читал.

Я знаю, что CommonJS (ранее ServerJS ) - это группа для определения некоторых спецификаций JavaScript (например, модулей), когда язык используется вне браузера. Спецификация модулей CommonJS имеет некоторую реализацию, такую ​​как Node.js или RingoJS , верно?

Какова связь между CommonJS , определением асинхронного модуля (AMD) и RequireJS ?

Является ли RequireJS реализацией определения модуля CommonJS ? Если да, то что такое AMD ?

Gremo
источник
31
Чтение requirejs.org/docs/whyamd.html многое прояснит, поскольку в нем упоминаются все из них. (отправив это как комментарий, поскольку я не считаю это полным ответом).
mmutilva
5
Могу я спросить или добавить больше; Как или где заявления ES2015 импорта вписываются во все это; например, импортировать Ember из 'ember';
testndtv
Существует также systemjs, который загружает любой из поддерживаемых форматов модулей JS, таких как (CommonJS, UMD, AMD, ES6).
Энди,

Ответы:

770

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 и превратилась в собственный API определения модулей. Отсюда сходство между ними. Новая функция в AMD - это define()функция, которая позволяет модулю объявлять свои зависимости перед загрузкой. Например, определение может быть:

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

Итак, CommonJS и AMD - это API определения модулей JavaScript, которые имеют разные реализации, но оба имеют одинаковое происхождение.

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

Я надеюсь, что это помогает уточнить вещи!

jakee
источник
7
Обратите внимание на проект uRequire.org, который устраняет пробелы в двух форматах - пишите в одном (или в обоих), разверните в любом из двух или в простом <script>
Ангелос Пикулас
51
К вашему сведению Browserify теперь позволит вам использовать CommonJS в браузере.
Eruant
9
@Eruant Но он все еще не такой асинхронный, как AMD.
Inanc Gumus
8
Причина, по которой CommonJS не помещается в браузере, указана в документе RequireJS: «CommonJS require () - это синхронный вызов, ожидается немедленный возврат модуля. Это плохо работает в браузере» . Больше информации здесь .
Мсенни
4
@aaaaaa вы можете включить некоторые функции в зависимости от запроса пользователя; так что асинхронная природа AMD может пригодиться.
Inanc Gumus
199

CommonJS - это нечто большее, это проект, который определяет общий API и экосистему для JavaScript. Одной из частей CommonJS является спецификация модуля . Node.js и RingoJS являются средами исполнения JavaScript на стороне сервера, и да, оба они реализуют модули, основанные на спецификации модуля CommonJS.

AMD (Asynchronous Module Definition) - это еще одна спецификация для модулей. RequireJS , пожалуй, самая популярная реализация AMD. Одним из основных отличий от CommonJS является то, что AMD указывает, что модули загружаются асинхронно - это означает, что модули загружаются параллельно, а не блокируют выполнение, ожидая завершения загрузки.

В связи с этим AMD чаще используется в разработке JavaScript на стороне клиента (в браузере), а модули CommonJS обычно используются на стороне сервера. Однако вы можете использовать любую спецификацию модуля в любой среде - например, RequireJS предлагает инструкции для запуска в Node.js, а browserify - это реализация модуля CommonJS, которая может работать в браузере.

Nate
источник
20
Почему домашняя страница CommonJS такая ужасная ... Я просто пытаюсь просмотреть официальную спецификацию. В нем есть синтаксические ошибки, неполная документация и страница вики не разрешается.
Тако
7
Это не то, что означает загружать модули асинхронно. Вы можете говорить о динамической / отложенной загрузке. При использовании async вы предлагаете файл для загрузки, а затем через некоторое время он перезвонит после завершения загрузки. При синхронизации вы предлагаете загрузить файл, а затем блокировать весь поток, пока этот файл не завершит загрузку; дальнейший код не выполняется до тех пор, пока файл не загрузится. Первый может дать лучшую производительность за счет непредсказуемости, в то время как второй может давать одинаковые результаты каждый раз и, таким образом, является более предсказуемым. Обратите внимание, что эти причуды могут быть смягчены с помощью различных оптимизаций.
Перри
Спасибо за ответ. Теперь, когда официальные модули в JS с ES2015 являются официальными, означает ли это, что они предпочтительнее, чем AMD или обычные JS?
Ахой,
Это не значит, что они предпочтительнее. Все зависит от потребностей разработчика. Я не думаю, что оставить хорошую опцию и перейти на модули ES6 - это особенно хорошая идея. Однако, используя хороший UMD, вы можете бороться с этой проблемой. Загрузка пакетов CommonJS, синхронизированных с AMD, - это хорошая (лучшая) идея в целом (для улучшения производительности). Если вы чувствуете, что должны иметь больше контроля, очевидно. И ты должен.
Мацей Ситко
187

Краткий ответ:

CommonJS и AMD - это спецификации (или форматы) того, как модули и их зависимости должны быть объявлены в приложениях javascript.

RequireJS - это библиотека загрузчиков скриптов, совместимая с AMD, еще одним примером является curljs .

CommonJS-совместимый:

Взято из книги Адди Османи .

// 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.

Источники:

mmutilva
источник
1
Видеть код, а не описания помогает! :) AMD compliantна самом деле это RequireJS, верно?
Asim KT
Я что-то упустил или что-то опечатано? Вы определяете «package / lib», но затем требуете «package / myModule».
RullDawg
Мне всегда нравится читать немного об истории, почему что-то так, как оно есть! Спасибо за предоставление этого фона!
Андру
@RullDawg Нет, «пакет / Библиотека» не определена здесь, это третья зависимость стороны используется здесь.
Роберт Симер
28

квотирование

AMD :

  • Один браузер-первый подход
  • Выбор асинхронного поведения и упрощенной обратной совместимости
  • У этого нет никакого понятия Файлового ввода-вывода.
  • Он поддерживает объекты, функции, конструкторы, строки, JSON и многие другие типы модулей.

CommonJS :

  • Один сервер-первый подход
  • Предполагая синхронное поведение
  • Охватите более широкий круг проблем, таких как ввод-вывод, файловая система, обещания и многое другое.
  • Поддерживает развернутые модули, может показаться немного ближе к спецификациям ES.next/Harmony , освобождая вас от оболочки define (), который AMDобеспечивает.
  • Поддерживайте только объекты как модули.
zangw
источник
17

Вполне нормально организовать модульную программу JavaScript в несколько файлов и вызывать child-modulesиз нее main js module.

Дело в том, что JavaScript этого не обеспечивает. Даже сегодня в последних версиях браузера Chrome и FF.

Но есть ли в JavaScript ключевое слово для вызова другого модуля JavaScript?

Этот вопрос может быть полным крахом мира для многих, потому что ответ - нет .


В ES5 (выпущенной в 2009 году) в JavaScript не было ключевых слов, таких как import , include или require .

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 для умной загрузки модулей.

прости
источник
3
Следует обновить ваш ответ, потому что теперь все современные браузеры поддерживают import
vsync
@vsync, да, не стесняйтесь редактировать мой ответ, так как я не следил за этим сегментом в течение некоторого времени.
прости