Зв'язок між CommonJS, AMD та RequireJS?


840

Я все ще дуже розгублений щодо CommonJS, AMD та RequireJS , навіть читаючи багато.

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

Яке відношення між CommonJS , визначенням асинхронного модуля (AMD) та RequireJS ?

Чи є RequireJS реалізацією визначення модуля CommonJS ? Якщо так, що тоді AMD ?


31
Читання Requjs.org/docs/whyamd.html могло б багато прояснити, оскільки воно згадує про них. (розміщую це як коментар, оскільки я не вважаю це повноцінною відповіддю).
mmutilva

5
Чи можу я запитати чи додати більше; Яким чином або де вказуються дані про імпорт ES2015 до всіх цих питань; наприклад, імпортувати Ember з 'ember';
testndtv

Існує також systemjs, який завантажує будь-який з підтримуваних форматів модулів JS, таких як (CommonJS, UMD, AMD, ES6).
Енді

Відповіді:


770

RequireJS реалізує API AMD (джерело) .

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

Я сподіваюся, що це допомагає з’ясувати речі!


7
Ознайомтеся з проектом uRequire.org , який подолає прогалини двох форматів - пишіть у будь-якому (або в обох), розгортайтеся до будь-якого з двох або простих <script>
Angelos Pikoulas

51
FYI Browserify тепер дозволить вам використовувати CommonJS у веб-переглядачі.
Еруант

9
@Eruant Але це все ще не така асинхронна природа, як AMD.
Інанк Гамус

8
Причина, чому CommonJS не вміщується в браузері, як зазначено в документах RequireJS, - "CommonJS вимагає () - це синхронний дзвінок, очікується, що він поверне модуль негайно. Це не працює добре в браузері" . Більше інформації тут .
msenni

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, а перегляд - це реалізація модуля CommonJS, який може працювати в браузері.


20
Чому домашня сторінка CommonJS така жахлива ... Я просто намагаюся переглянути офіційну специфікацію. У ньому є синтаксичні помилки, неповна документація і вікі-сторінка не вирішується.
тако

7
Це не те, що означає асинхронно завантажувати модулі. Ви можете говорити про динамічне / ледаче завантаження. За допомогою async ви пропонуєте файл завантажувати, а потім через деякий час він передзвонить, коли закінчиться завантаження. За допомогою синхронізації ви пропонуєте завантажувати файл, а потім весь блок потоків, поки цей файл не завершиться завантаженням; подальший код не виконується, поки файл не завантажується. Перші можуть давати кращі показники за рахунок непередбачуваності, тоді як другі можуть давати однакові результати щоразу і, таким чином, є більш передбачуваними. Зауважте, ці примхи можна зменшити за допомогою різних оптимізацій.
perry

Дякую за відповідь. Тепер, коли модулі є офіційними в 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.

Джерела:


1
Перегляд коду, а не опису, допомагає! :) AMD compliantнасправді RequireJS, правда?
Асім КТ

Я щось пропускаю, чи щось неправильно вводиться? Ви визначаєте "package / lib", але потім вимагаєте "package / myModule".
RullDawg

Мені завжди подобається читати трохи про історію, чому щось так і є! Дякуємо, що надали цей фон!
Андру

@RullDawg Ні, «пакет / Бібліотека» не визначена тут, це третя залежність боку використовується тут.
Роберт Сімер

28

Цитуючи

AMD :

  • Один підхід для браузера
  • Вибір асинхронної поведінки та спрощена зворотна сумісність
  • У ньому немає жодної концепції File I / O.
  • Він підтримує об'єкти, функції, конструктори, рядки, JSON та багато інших типів модулів.

CommonJS :

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

17

Цілком нормально організувати програму 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 "дефект" для завантаження модулів.


3
Слід оновити свою відповідь, оскільки тепер підтримуються всі сучасні браузериimport
vsync

@vsync, так, не соромтесь редагувати мою відповідь, оскільки я не слідкував за цим сегментом деякий час.
prosti
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.