javascript - Forholdet mellom CommonJS, AMD og RequireJS?


Jeg er fortsatt veldig forvirret over CommonJS, AMD og RequireJS, selv etter å ha lest mye.

Jeg vet at CommonJS (tidligere ServerJS) er en gruppe for å definere noen JavaScript-spesifikasjoner (dvs. moduler) når språket brukes utenfor nettleseren. CommonJS-modulspecifikasjonen har noen implementasjoner som Node.js eller RingoJS, ikke sant?

Hva er forholdet mellom CommonJS, Asynchronous Module Definition (AMD) og RequireJS?

Er RequireJS en implementering av CommonJS-moduldefinisjonen? Hvis ja, hva er AMD da?

Svar #1

RequireJS implementerer AMD-APIet (kilde).

CommonJS er en måte å definere moduler på ved hjelp av et exports-objekt, som definerer modulens innhold. Kort sagt kan en CommonJS-implementering fungere slik:

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

I utgangspunktet spesifiserer CommonJS at du må ha en require()-funksjon for å hente avhengigheter, en exports-variabel for å eksportere modulinnhold og en modulidentifikator (som beskriver plasseringen av modulen det gjelder i forhold til denne modulen) som brukes for å kreve avhengighetene (kilde). CommonJS har ulike implementasjoner, inkludert Node.js, som du nevnte.

CommonJS var ikke spesielt designet med nettlesere i tankene, så det passer ikke særlig godt i nettlesermiljøet (*jeg har egentlig ingen kilde for dette--det står bare overalt, inkludert på RequireJS-nettstedet.*) Tilsynelatende har dette noe å gjøre med asynkron lasting, osv.

På den annen side implementerer RequireJS AMD, som er designet for å passe til nettlesermiljøet (kilde). Tilsynelatende startet AMD som en avspaltning av CommonJS Transport-formatet og utviklet seg til sin egen moduldefinisjons-API. Dermed likhetene mellom de to. Den nye funksjonen i AMD er define()-funksjonen som lar modulen deklarere sine avhengigheter før den lastes. For eksempel kunne definisjonen være:

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

Så, CommonJS og AMD er JavaScript-moduldefinisjons-APIer som har forskjellige implementasjoner, men begge har samme opprinnelse.

  • AMD er mer egnet for nettleseren, fordi det støtter asynkron innlasting av modulavhengigheter.
  • RequireJS er en implementasjon av AMD, samtidig som den prøver å bevare ånden til CommonJS (hovedsakelig i modulidentifikatorene).

For å forvirre deg enda mer tilbyr RequireJS, mens det er en AMD-implementering, en CommonJS-innpakning slik at CommonJS-moduler nesten direkte kan importeres for bruk med RequireJS.

define(function(require, exports, module) {
  var someModule = require('someModule'); // in the vein of node    
  exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };
});

Svar #2

CommonJS er mer enn det - det er et prosjekt for å definere et felles API og økosystem for JavaScript. En del av CommonJS er Modulspesifikasjonen. Node.js og RingoJS er server-side JavaScript-kjøretider, og ja, begge implementerer moduler basert på CommonJS Modulspesifikasjon.

AMD (Asynchronous Module Definition) er en annen spesifikasjon for moduler. RequireJS er sannsynligvis den mest populære implementeringen av AMD. En viktig forskjell fra CommonJS er at AMD spesifiserer at moduler lastes asynkront - det betyr at moduler lastes parallelt, i motsetning til å blokkere utførelsen ved å vente på at en lasting skal fullføres.

AMD brukes generelt mer i klient-side (i-nettleser) JavaScript-utvikling på grunn av dette, og CommonJS-moduler brukes generelt server-side. Du kan imidlertid bruke hvilken som helst modulspesifikasjon i begge miljøer - for eksempel tilbyr RequireJS veiledning for kjøring i Node.js, og browserify er en CommonJS-modulimplementasjon som kan kjøre i nettleseren.

Svar #3

Det korte svaret vil være:

CommonJS og AMD er spesifikasjoner (eller formater) for hvordan moduler og deres avhengigheter skal deklareres i Javascript-applikasjoner.

RequireJS er et skriptlasterbibliotek som er AMD-kompatibelt, curljs er et annet eksempel.

CommonJS-kompatibel:

Hentet fra Addy Osmanis bok.

// 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-kompatibel:

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

Et annet sted kan modulen brukes med:

require(["package/myModule"], function(myModule) {
    myModule.foobar();
});

Litt bakgrunn:

Faktisk er CommonJS mye mer enn en API-deklarasjon, og bare en del av det handler om det. AMD startet som et utkast til spesifikasjon for modulf-formatet på CommonJS-listen, men full enighet ble ikke oppnådd, og videre utvikling av formatet ble flyttet til amdjs-gruppen. Argumenter rundt hvilket format som er bedre hevder at CommonJS forsøker å dekke et bredere sett med hensyn og at det er bedre egnet for server-side utvikling gitt dets synkrone natur, mens AMD er bedre egnet for klient-side (nettleser) utvikling gitt dets asynkrone natur og det faktum at det har sine røtter i Dojos modulkonstruksjonsimplementering.

Kilder :

  • RequireJS - Hvorfor AMD?
  • Addy Osmani - Lære JavaScript Designmønstre - Moderne modulære JavaScript-designmønstre

Svar #4

Sitering

AMD:

  • En nettleser-først tilnærming
  • Å velge asynkron oppførsel og forenklet bakoverkompatibilitet
  • Den har ingen forståelse av filinn-/utdata.
  • Den støtter objekter, funksjoner, konstruktører, strenger, JSON og mange andre typer moduler.

CommonJS:

  • En server-første tilnærming
  • Forutsatt synkron atferd
  • Dekke et bredere spekter av bekymringer som I/O, filsystem, løfter og mer.
  • Støtter uinnpakkede moduler, det kan føles litt nærmere ES.next/Harmony-spesifikasjonene, og frigjør deg fra define()-innpakningen som AMD pålegger.
  • Støtter kun objekter som moduler.

Svar #5

Det er ganske normalt å organisere et JavaScript-program modulært i flere filer og å kalle barne-moduler fra hoved js-modulen.

Saken er at JavaScript ikke tilbyr dette. Ikke engang i dag i de nyeste nettleserversjonene av Chrome og FF.

Men, finnes det noe nøkkelord i JavaScript for å kalle en annen JavaScript-modul?

Dette spørsmålet kan være en total verdenssammenbrudd for mange fordi svaret er Nei.


I ES5 (utgitt i 2009) hadde JavaScript ingen nøkkelord som import, include eller require.

ES6 redder dagen (utgitt i 2015) ved å foreslå import-nøkkelordet (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/import), og nå støtter alle moderne nettlesere dette.

Hvis du bruker Babel 6.18.0 og transpilerer kun med ES2015-alternativet

import myDefault from "my-module";

du vil få require igjen.

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

Dette er fordi require betyr at modulen vil bli lastet inn fra Node.js. Node.js vil håndtere alt fra systemnivå fillesing til innpakning av funksjoner i modulen.

Fordi i JavaScript er funksjoner de eneste innpakningene for å representere modulene.

Jeg er veldig forvirret om CommonJS og AMD?

Både CommonJS og AMD er bare to forskjellige teknikker for hvordan man kan overvinne JavaScript-«feilen» med å laste moduler på en smart måte.

Relaterte artikler