>웹 프론트엔드 >JS 튜토리얼 >JS(CommonJS, AMD, CMD)의 모듈 사양에 대한 자세한 설명

JS(CommonJS, AMD, CMD)의 모듈 사양에 대한 자세한 설명

php是最好的语言
php是最好的语言원래의
2018-08-07 09:21:442051검색

먼저 대답해 주세요: 모듈이 왜 중요한가요?

답변: 모듈 덕분에 우리는 다른 사람의 코드를 더 편리하게 사용할 수 있고, 우리가 원하는 기능에 대해 우리가 원하는 모듈을 로드할 수 있습니다.
하지만 여기에는 전제가 있습니다. 즉, 모든 사람이 같은 방식으로 모듈을 작성해야 한다는 것입니다. 그렇지 않으면 당신은 당신의 글쓰기 방식이 있고 나는 내 글쓰기 방식이 있으면 엉망이 되지 않을까요!

그래서 다음 세 가지 모듈이 표준화되었고, 이 글도 게재되었습니다({얼굴 가리고 웃는다}라고 표기).

JS 모듈 사양(CommonJS, AMD, CMD), js 모듈화에 대해 들어본 적이 있다면 CommonJS나 AMD, 심지어 CMD에 대해서도 들어봤을 것입니다. 방금 들었어. 이제 이러한 사양이 무엇인지, 어떤 역할을 하는지 살펴보겠습니다. 이 기사에는 이 세 가지 사양의 소스와 해당 제품의 원리가 포함되어 있습니다.

1. CommonJS

1. 처음에는 JS가 공식적으로 정의된 API는 브라우저 기반 애플리케이션만 구축할 수 있다고 생각했습니다. CommonJS는 너무 편협하고(고급 단어인 돌팔이를 사용함) CommonJS API는 일반 애플리케이션(주로 브라우저가 아닌 애플리케이션)에서 사용하는 많은 API를 정의하여 이러한 격차를 메워줍니다. 궁극적인 목표는 Python, Ruby 및 Java와 유사한 표준 라이브러리를 제공하는 것입니다. 이 경우 개발자는 CommonJS API를 사용하여 애플리케이션을 작성할 수 있으며, 이러한 애플리케이션은 다양한 JavaScript 인터프리터 및 다양한 호스트 환경에서 실행될 수 있습니다.

CommonJS와 호환되는 시스템에서는 JavaScript를 사용하여 다음 프로그램을 개발할 수 있습니다:

(1). 서버 측 JavaScript 애플리케이션

(2). 그래픽 인터페이스 애플리케이션
(4). 하이브리드 애플리케이션(예: Titanium 또는 Adobe AIR)

2009년 미국 프로그래머 Ryan Dahl은 서버 측 프로그래밍에 JavaScript 언어를 사용하기 위해 node.js 프로젝트를 만들었습니다. 이는 "Javascript 모듈러 프로그래밍"의 공식적인 탄생을 의미합니다. 솔직히 말해서 브라우저 환경에서는 모듈이 없어도 큰 문제가 되지 않습니다. 결국 웹 프로그램의 복잡성은 제한적이지만 서버 측에서는 운영 체제 및 기타 응용 프로그램과 상호 작용할 수 있는 모듈이 있어야 합니다. 그렇지 않으면 프로그래밍 방법이 없습니다. NodeJS는 CommonJS 스펙을 구현한 것이며, webpack도 CommonJS 형태로 작성되었습니다.

node.js의 모듈 시스템은 CommonJS 사양을 참조하여 구현되었습니다. CommonJS에는 모듈을 로드하는 데 사용되는 전역 메서드 require()가 있습니다. 수학 모듈 math.js가 있다고 가정하면 다음과 같이 로드할 수 있습니다.

var math = require('math');

그런 다음 모듈에서 제공하는 메서드를 호출할 수 있습니다:

 var math = require('math');

Math .add(2,3); // 5

CommonJS에서 정의한 모듈은 다음과 같이 나뉩니다. {모듈 참조(필수)} {모듈 정의(내보내기)} {모듈 식별(모듈)}

require( )는 외부 모듈을 소개하는 데 사용됩니다. 내보내기 개체는 현재 모듈의 메서드나 변수를 내보내는 데 사용됩니다. 유일한 내보내기 포트는 모듈 자체를 나타냅니다.

Node는 CommonJS의 사양을 따르지만 몇 가지 절충안을 만들고 몇 가지 새로운 사항을 추가했습니다.

하지만 CommonJS에 대해 이야기하고 Node에 대해서도 이야기한 후에 NPM을 먼저 이해해야 한다고 생각합니다. NPM은 Node의 패키지 관리자로서 Node가 종속 패키지의 설치 문제를 해결하도록 돕는 것이 아니라 CommonJS 사양(또는 이론)을 따라야 합니다. CommonJS WIKI는 그 역사에 대해 이야기하고, 모듈, 패키지 등을 소개합니다.

commonJS의 원리와 간단한 구현에 대해 이야기해 보겠습니다.

1. 원리

브라우저가 CommonJS와 호환되지 않는 근본적인 이유는 4개의 Node.js 환경 변수가 부족하기 때문입니다.

  • module

  • exports

  • require

  • global

이 네 가지 변수를 제공할 수 있는 한 브라우저는 CommonJS 모듈을 로드할 수 있습니다.

다음은 간단한 예입니다.

<code class="language-javascript"><span style="font-family:'Microsoft YaHei';font-size:16px;"><code class="language-javascript"><br><span class="token keyword">var module <span class="token operator">= <span class="token punctuation">{<br> exports<span class="token punctuation">: <span class="token punctuation">{<span class="token punctuation">}<br><span class="token punctuation">}<span class="token punctuation">;<br><br><span class="token punctuation">(<span class="token keyword">function<span class="token punctuation">(module<span class="token punctuation">, exports<span class="token punctuation">) <span class="token punctuation">{<br> exports<span class="token punctuation">.multiply <span class="token operator">= <span class="token keyword">function <span class="token punctuation">(n<span class="token punctuation">) <span class="token punctuation">{ <span class="token keyword">return n <span class="token operator">* <span class="token number">1000 <span class="token punctuation">}<span class="token punctuation">;<br><span class="token punctuation">}<span class="token punctuation">(module<span class="token punctuation">, module<span class="token punctuation">.exports<span class="token punctuation">)<span class="token punctuation">)<br><br><span class="token keyword">var f <span class="token operator">= module<span class="token punctuation">.exports<span class="token punctuation">.multiply<span class="token punctuation">;<br><span class="token function">f<span class="token punctuation">(<span class="token number">5<span class="token punctuation">)<span class="token comment"> // 5000 <br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></span></code>

위의 코드는 즉시 실행 함수에 두 개의 외부 변수인 module과 내보내기를 제공하고, 모듈은 이 즉시 실행 함수에 배치됩니다. 모듈의 출력 값은 module.exports에 배치되어 모듈 로딩을 구현합니다.

2. Browserify 구현

원리를 알면 도구를 만들 수 있습니다. Browserify는 현재 가장 일반적으로 사용되는 CommonJS 형식 변환 도구입니다.

main.js 모듈이 foo.js 모듈을 로드하는 예를 참조하세요.

<code class="language-javascript"><span style="font-family:'Microsoft YaHei';font-size:16px;"><code class="language-javascript"><span class="token comment"><br>// foo.js<br>module<span class="token punctuation">.exports <span class="token operator">= <span class="token keyword">function<span class="token punctuation">(x<span class="token punctuation">) <span class="token punctuation">{<br> console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(x<span class="token punctuation">)<span class="token punctuation">;<br><span class="token punctuation">}<span class="token punctuation">;<br><span class="token comment"><br>// main.js<br><span class="token keyword">var foo <span class="token operator">= <span class="token function">require<span class="token punctuation">(<span class="token string">"./foo"<span class="token punctuation">)<span class="token punctuation">;<br><span class="token function">foo<span class="token punctuation">(<span class="token string">"Hi"<span class="token punctuation">)<span class="token punctuation">;<br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></span></code>

main.js를 브라우저에서 사용할 수 있는 형식으로 변환하려면 다음 명령을 사용하세요.

<span style="font-family:&#39;Microsoft YaHei&#39;;font-size:16px;"><code class="language-bash"><br/>$ browserify main<span class="token punctuation">.js <span class="token operator">> compiled<span class="token punctuation">.js<br/></span></span></span></code></span>

Browserify의 기능은 정확히 무엇인가요? browser-unpack을 설치하시면 선명하게 보실 수 있습니다.

<span style="font-family:&#39;Microsoft YaHei&#39;;font-size:16px;"><code class="language-bash"><br/>$ npm install browser<span class="token operator">-unpack <span class="token operator">-g<br/></span></span></code></span>

그런 다음 앞서 생성한 compile.js의 압축을 풀어주세요.

<span style="font-family:&#39;Microsoft YaHei&#39;;font-size:16px;"><code class="language-bash"><br/>$ browser<span class="token operator">-unpack <span class="token operator">< compiled<span class="token punctuation">.js<br/><br/><span class="token punctuation">[<br/><span class="token punctuation">{<br/><span class="token string">"id"<span class="token punctuation">:<span class="token number">1<span class="token punctuation">,<br/><span class="token string">"source"<span class="token punctuation">:<span class="token string">"module.exports = function(x) {\n console.log(x);\n};"<span class="token punctuation">,<br/><span class="token string">"deps"<span class="token punctuation">:<span class="token punctuation">{<span class="token punctuation">}<br/><span class="token punctuation">}<span class="token punctuation">,<br/><span class="token punctuation">{<br/><span class="token string">"id"<span class="token punctuation">:<span class="token number">2<span class="token punctuation">,<br/><span class="token string">"source"<span class="token punctuation">:<span class="token string">"var foo = require(\"./foo\");\nfoo(\"Hi\");"<span class="token punctuation">,<br/><span class="token string">"deps"<span class="token punctuation">:<span class="token punctuation">{<span class="token string">"./foo"<span class="token punctuation">:<span class="token number">1<span class="token punctuation">}<span class="token punctuation">,<br/><span class="token string">"entry"<span class="token punctuation">:<span class="token boolean">true<br/><span class="token punctuation">}<br/><span class="token punctuation">]<br/></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></span>

보시다시피 browerify는 모든 모듈을 배열에 넣습니다. id 속성은 모듈 번호이고, source 속성은 모듈의 소스 코드이며, deps 속성은 모듈의 종속성입니다. 기준 치수.

foo.js가 main.js에 로드되기 때문에 deps 속성은 ./foo가 모듈 번호 1에 해당함을 지정합니다. 실행 중 브라우저는 require('./foo') 문을 만나면 자동으로 1번 모듈의 source 속성을 실행하고 실행된 module.exports 속성 값을 출력합니다.

3. Tiny Browser Require

Browserify는 매우 강력하지만 브라우저에서 작동할 수 없어 때로는 매우 불편합니다.

모카 내부 구현을 기반으로 순수 브라우저 CommonJS 모듈 로더tiny-browser-require를 만들었습니다. 명령줄이 전혀 필요하지 않고 브라우저에 직접 입력하면 됩니다. 전체 코드는 30줄이 넘습니다.

논리는 매우 간단합니다. 즉, 모듈을 배열로 읽어들이고 로딩 경로는 모듈의 ID입니다.

<code class="language-javascript"><span style="font-family:'Microsoft YaHei';font-size:16px;"><code class="language-javascript"><br><span class="token keyword">function <span class="token function">require<span class="token punctuation">(p<span class="token punctuation">)<span class="token punctuation">{<br><span class="token keyword">var path <span class="token operator">= require<span class="token punctuation">.<span class="token function">resolve<span class="token punctuation">(p<span class="token punctuation">)<span class="token punctuation">;<br><span class="token keyword">var mod <span class="token operator">= require<span class="token punctuation">.modules<span class="token punctuation">[path<span class="token punctuation">]<span class="token punctuation">;<br><span class="token keyword">if <span class="token punctuation">(<span class="token operator">!mod<span class="token punctuation">) <span class="token keyword">throw <span class="token keyword">new <span class="token class-name">Error<span class="token punctuation">(<span class="token string">'failed to require "' <span class="token operator">+ p <span class="token operator">+ <span class="token string">'"'<span class="token punctuation">)<span class="token punctuation">;<br><span class="token keyword">if <span class="token punctuation">(<span class="token operator">!mod<span class="token punctuation">.exports<span class="token punctuation">) <span class="token punctuation">{<br> mod<span class="token punctuation">.exports <span class="token operator">= <span class="token punctuation">{<span class="token punctuation">}<span class="token punctuation">;<br> mod<span class="token punctuation">.<span class="token function">call<span class="token punctuation">(mod<span class="token punctuation">.exports<span class="token punctuation">, mod<span class="token punctuation">, mod<span class="token punctuation">.exports<span class="token punctuation">, require<span class="token punctuation">.<span class="token function">relative<span class="token punctuation">(path<span class="token punctuation">)<span class="token punctuation">)<span class="token punctuation">;<br><span class="token punctuation">}<br><span class="token keyword">return mod<span class="token punctuation">.exports<span class="token punctuation">;<br><span class="token punctuation">}<br><br>require<span class="token punctuation">.modules <span class="token operator">= <span class="token punctuation">{<span class="token punctuation">}<span class="token punctuation">;<br><br>require<span class="token punctuation">.resolve <span class="token operator">= <span class="token keyword">function <span class="token punctuation">(path<span class="token punctuation">)<span class="token punctuation">{<br><span class="token keyword">var orig <span class="token operator">= path<span class="token punctuation">;<br><span class="token keyword">var reg <span class="token operator">= path <span class="token operator">+ <span class="token string">'.js'<span class="token punctuation">;<br><span class="token keyword">var index <span class="token operator">= path <span class="token operator">+ <span class="token string">'/index.js'<span class="token punctuation">;<br><span class="token keyword">return require<span class="token punctuation">.modules<span class="token punctuation">[reg<span class="token punctuation">] <span class="token operator">&& reg<br><span class="token operator">|| require<span class="token punctuation">.modules<span class="token punctuation">[index<span class="token punctuation">] <span class="token operator">&& index<br><span class="token operator">|| orig<span class="token punctuation">;<br><span class="token punctuation">}<span class="token punctuation">;<br><br>require<span class="token punctuation">.register <span class="token operator">= <span class="token keyword">function <span class="token punctuation">(path<span class="token punctuation">, fn<span class="token punctuation">)<span class="token punctuation">{<br> require<span class="token punctuation">.modules<span class="token punctuation">[path<span class="token punctuation">] <span class="token operator">= fn<span class="token punctuation">;<br><span class="token punctuation">}<span class="token punctuation">;<br><br>require<span class="token punctuation">.relative <span class="token operator">= <span class="token keyword">function <span class="token punctuation">(parent<span class="token punctuation">) <span class="token punctuation">{<br><span class="token keyword">return <span class="token keyword">function<span class="token punctuation">(p<span class="token punctuation">)<span class="token punctuation">{<br><span class="token keyword">if <span class="token punctuation">(<span class="token string">'.' <span class="token operator">!<span class="token operator">= p<span class="token punctuation">.<span class="token function">charAt<span class="token punctuation">(<span class="token number">0<span class="token punctuation">)<span class="token punctuation">) <span class="token keyword">return <span class="token function">require<span class="token punctuation">(p<span class="token punctuation">)<span class="token punctuation">;<br><span class="token keyword">var path <span class="token operator">= parent<span class="token punctuation">.<span class="token function">split<span class="token punctuation">(<span class="token string">'/'<span class="token punctuation">)<span class="token punctuation">;<br><span class="token keyword">var segs <span class="token operator">= p<span class="token punctuation">.<span class="token function">split<span class="token punctuation">(<span class="token string">'/'<span class="token punctuation">)<span class="token punctuation">;<br> path<span class="token punctuation">.<span class="token function">pop<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;<br><br><span class="token keyword">for <span class="token punctuation">(<span class="token keyword">var i <span class="token operator">= <span class="token number">0<span class="token punctuation">; i <span class="token operator">945e8d4292ce0af7e515c6c2ee692956<br><br>3f1c4e4b6b16bbbd69b2ee476dc4f83a<br>require.register("moduleId", function(module, exports, require){<br> // Module code goes here<br>});<br>var result = require("moduleId");<br>2cacc6d41bbb37262a98f745aa00fbf0<br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></span></code>

 还是以前面的 main.js 加载 foo.js 为例。

<code class="language-javascript"><span style="font-family:'Microsoft YaHei';font-size:16px;"><code class="language-javascript"><br>require<span class="token punctuation">.<span class="token function">register<span class="token punctuation">(<span class="token string">"./foo.js"<span class="token punctuation">, <span class="token keyword">function<span class="token punctuation">(module<span class="token punctuation">, exports<span class="token punctuation">, require<span class="token punctuation">)<span class="token punctuation">{<br> module<span class="token punctuation">.exports <span class="token operator">= <span class="token keyword">function<span class="token punctuation">(x<span class="token punctuation">) <span class="token punctuation">{<br> console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(x<span class="token punctuation">)<span class="token punctuation">;<br><span class="token punctuation">}<span class="token punctuation">;<br><span class="token punctuation">}<span class="token punctuation">)<span class="token punctuation">;<br><br><span class="token keyword">var foo <span class="token operator">= <span class="token function">require<span class="token punctuation">(<span class="token string">"./foo.js"<span class="token punctuation">)<span class="token punctuation">;<br><span class="token function">foo<span class="token punctuation">(<span class="token string">"Hi"<span class="token punctuation">)<span class="token punctuation">;<br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></span></code>

 注意,这个库只模拟了 require 、module 、exports 三个变量,如果模块还用到了 global 或者其他 Node 专有变量(比如 process),就通过立即执行函数提供即可。

二、AMD

基于commonJS规范的nodeJS出来以后,服务端的模块概念已经形成很自然地,大家就想要客户端模块。而且最好两者能够兼容,一个模块不用修改,在服务器和浏览器都可以运行。但是,由于一个重大的局限,使得CommonJS规范不适用于浏览器环境。还是上面的代码,如果在浏览器中运行,会有一个很大的问题,你能看出来吗?

  var math = require('math');

  math.add(2, 3);

 第二行math.add(2, 3),在第一行require('math')之后运行,因此必须等math.js加载完成。也就是说,如果加载时间很长,整个应用就会停在那里等。您会注意到 require 是同步的。

这对服务器端不是一个问题,因为所有的模块都存放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间。但是,对于浏览器,这却是一个大问题,因为模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于"假死"状态。

 因此,浏览器端的模块,不能采用"同步加载"(synchronous),只能采用"异步加载"(asynchronous)。这就是AMD规范诞生的背景。

CommonJS是主要为了JS在后端的表现制定的,他是不适合前端的,AMD(异步模块定义)出现了,它就主要为前端JS的表现制定规范。

AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:

  require([module], callback);

第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。如果将前面的代码改写成AMD形式,就是下面这样:

  require(['math'], function (math) {

    math.add(2, 3);

  });

math.add() 및 수학 모듈 로딩이 동기화되지 않아 브라우저가 정지되지 않습니다. 따라서 분명히 AMD는 브라우저 환경에 더 적합합니다. 현재 AMD 사양을 구현하는 두 가지 주요 Javascript 라이브러리는 require.js와curl.js입니다.

RequireJS는 AMD 사양을 구현합니다.

상세 요약: 다음은 RequireJS를 예로 들어 AMD 사양을 설명합니다

1. require.js를 사용하는 이유는 무엇입니까?

초창기에는 모든 Javascript 코드가 하나의 파일에 작성되어 있었는데, 이 파일 하나만 로드해도 충분했습니다. 나중에는 코드가 점점 많아져서 하나의 파일로는 더 이상 부족해 여러 파일로 나누어 순차적으로 로드해야 했습니다. 많은 분들이 다음 웹페이지 코드를 보셨으리라 믿습니다

 82aa3526d91a1e63399c31e3e88e82b62cacc6d41bbb37262a98f745aa00fbf0