본문으로 건너뛰기

module_ES6 노트 13

무료2016-10-29#JS#es6模块语法#js模块化#es6模块与AMD#es6模块与CommonJS#es6模块机制

정적 모듈 메커니즘

서문에

이것은 ES6 노트의 마지막 콘텐츠로, 유일하게장래에만 사용 가능한 특성입니다

장래는 언제일까요?

아마도 HTTP2 가 보급될 때일 것입니다. 하지만 더 가능성이 높은 것은 장래에도 "사용할 수 없다"(여전히 빌드 도구에서만 사용 가능하고, "컴파일기"에만 존재함)는 것입니다

一.AMD, CMD 와 CommonJS

AMD/CMD, 약간의 확장 지식은 다음과 같습니다:

CommonJS 는 한整套의 이론 규범(예를 들어 js 의 이론 규범은 ES)이고, SeaJS, RequireJS 는 모두 CommonJS 의 Modules 부분의 구체적 구현입니다

CommonJS 는 브라우저 외 (server 단) 를 향한 js 에 대해 제정된 것으로, 동기 모듈 로드입니다. SeaJS 는 CommonJS 의 하나의 구현이고, RequireJS 도 CommonJS 의 하나의 구현이지만, 비동기 모듈 로드로, 브라우저의 싱글스레드 환경에 더贴近합니다

요약:CommonJS 의 Modules 부분은 모듈화 코드 관리의 이론을 제출하여, js 를 모듈화 로드할 수 있게 했습니다. RequireJS, SeaJS 등의 각종 구현은 모듈화 스크립트 로더라고 부를 수 있습니다

CMD:Common 모듈 정의, 예를 들어 SeaJS

AMD:비동기 모듈 정의, 예를 들어 RequireJS

모두 코드 모듈을 정의하는 한整套의 규범으로, 모듈화 스크립트 로드에 편리하고, 응답 속도를 향상

CMD 와 AMD 의 차이:

CMD 는 의존을就近에. 사용에 편리하고, 모듈 내부에서 수시수소에 취득할 수 있고, 사전에 의존 항목을 선언할 필요가 없으므로, 성능 면에서 약간의 저하가 있습니다(모듈 전체를 주사하여 의존 항목을 찾을 필요가 있습니다)

AMD 는 의존을 전치에. 엄격하게 의존 항목을 선언할 필요가 있고, 로직 내부의 의존 항목(연의존)에 대해서는, 비동기 로드, 콜백 처리의 방식으로 해결합니다

([JS 프로그래밍 상식](/articles/js 프로그래밍 상식/#articleHeader9) 에서 발췌)

JS 모듈화에 관심을 가졌다면, 이 세 가지의 혼란스러운 관계를 분명히 알고 있을 것입니다. ES6 모듈은 표준을 통해 이 혼란을 종결시키기를 희망합니다

二.ES6 모듈 구문

1.모듈 작용역

module 은 모듈 작용역을 도입하며, 특징은 다음과 같습니다:

  • 현재(2016/1/31 2016/10/29)브라우저는 ES6 모듈을 지원하지 않습니다(아마도 이러한 모듈 로드 메커니즘은 브라우저 환경에 적합하지 않음), webpack 등의 도구를 이용하여 import 의 모든 내용을 하나의 파일에 통합할 수 있습니다

  • ES6 모듈은 기본적으로 엄격 모드로, 'use strict'; 를 추가하는지 여부와 관계없이

  • 도입/导出 시 리네임을 지원, import/export {api as newApi}, 도입 시 리네임은 주로 명명 충돌을 해결하고, 导出 시 리네임은 별명($jQuery)을 구현

  • 기본 도입/导出를 지원, CommonJS 와 AMD 모듈을 도입 가능

  • import/export 를 사용할 수 있는 것은 모듈의 최외층 작용역のみ로, 조건문에서 사용할 수 없습니다

요약:엄격 모드를 추진;CommonJS 와 AMD 와 호환;단순한정적 모듈 메커니즘으로, 按需 로드 등의 문제를 해결하지 않음

도입/导出 시 리네임, 예는 다음과 같습니다:

// 도입 시 리네임, 명명 충돌 해결
import {flip as flipOmelet} from "eggs.js";
import {flip as flipHouse} from "real-estate.js";

// 导出 시 리네임, 별명 구현
function v1() { ... }
function v2() { ... }
export {
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
};

2.import

import {api1, api2...} from 'xxx.js' 구문, 특징은 다음과 같습니다:

  • api 부분 도입을 지원(필요 없는 기능 인터페이스를 도입하지 않음, 물론, xxx.js 는 완전히 로드되고, 부분 도입은 작용역 제어일 뿐)

  • xxx.js 에さらに import 문이 있는 경우, 깊이 우선으로 로드 실행

  • 실행済み 모듈은 무시되어, 순환 인용을 형성하는 것을 회피

  • 기본 도입을 지원, CommonJS 와 AMD 패키지를 도입하는 데 사용(defaultexport 오브젝트), import api from 'xxx.js'import {default as api} from 'xxx.js' 와 동등

  • 모듈 오브젝트의 도입을 지원, import * as apis from 'xxx.js', *xxx.js 중의 export 의 모든 것을 나타내며, xxx.js 에서导出된 모든 것을 apis 오브젝트에 통합하고, apis.xx 를 통해 액세스

요약:로드 메커니즘은 CSS 의 @import 와 유사하고, 순환 의존을 처리하는 방식도 유사;同样 CommonJS 와 AMD 와 호환

작용역 레벨에서 부분 도입을 지원, 유용하지만, 의미는 크지 않고, 빌드 도구와 배합하여 컴파일 시에 "전지"(tree shaking)하는 것이 더 좋음

3.export

export {api1, api2...} 구문, 특징은 다음과 같습니다:

  • 수행에서 선언할 필요가 없고, 모듈 내외층 작용역임의의 위치에서 export 가능

  • 복수의 export 를 선언 가능하지만, api 명칭이 중복되지 않음을 보증할 필요가 있고, 명칭이 중복되면 오류가 발생할 수 있음

  • 기본导出를 지원, export default api 또는 export {api as default}

  • 聚合导出를 지원, export {api1, api2...} from 'xxx.js'import + export 와 동등하지만, export from 은当前모듈 작용역에 각 api 변수를 도입하지 않음(도입 후 직접导出, 인용 불가

  • export 가导出하는 api 리스트는 리터럴 형식이어야 하고, 배열을 주사하여 배열 요소를导出할 수 없음

요약:로드 시 export 리스트를 정리하므로, 외층 임의의 위치에서 export 가능;聚合을 지원, 각 제 3 자 모듈에서 일부를 꺼내어 통합;정적 제한, 동적导出를 허용하지 않음

예는 다음과 같습니다:

// 기본导出
 let myObject = {
  field1: value1,
  field2: value2
};
export {myObject as default};
// 동등
export default {
  field1: value1,
  field2: value2
};

// 聚合导出
// "sri-lanka" 를 도입하고, 그것이导出한 내용의 일부를 재导出
export {Tea, Cinnamon} from "sri-lanka";
// "equatorial-guinea" 를 도입하고, 그것이导出한 내용의 일부를 재导出
export {Coffee, Cocoa} from "equatorial-guinea";
// "singapore" 를 도입하고, 그것이导出한 내용의 모두를导出
export * from "singapore";

三.모듈 실행 메커니즘

ES6 표준은 구체적 모듈 로드 메커니즘을 명기하지 않고, 최종 구현에 위임하지만, 모듈 실행 메커니즘을 명확히 규정하고, 4 개의 스텝으로 나뉩니다

  1. 구문 해석

구문 오류를 체크

  1. 로드

모든 import 된 것을 재귀적으로 로드, 구체적으로 어떻게 로드하는지, 명기하지 않음, 완전히 최종 구현에 위임

  1. 연결

모듈 작용역을 생성하고, 모든 import 된 것을 작용역에 쑤셔 넣음

import 이 오류인 경우, 오류를 트리거, 구체적 행위는 미지(아직 브라우저가 제 2 보를 걷은 적이 없기 때문)

  1. 런타임

각 모듈의 모든 문을 실행, 이 때 import/export 에 조우하면 무시, 모듈 관련의 처리는 이미 종료되었기 때문

정적 제한

  • import/export 를 사용할 수 있는 것은 모듈 최외층 작용역のみ로, 조건문에서 사용할 수 없고, 함수 작용역에서도 사용할 수 없음

  • export 의 식별자는 리터럴 형식이어야 함(소스 코드 중에 대응하는 선언이 있음), 배열을 주사하여 일련의 것을导出할 수 없음

  • 모듈 오브젝트는 동결되어, 모듈 오브젝트를 hack 하여 polyfill 스타일의 신특성을 추가할 수 없음

  • 모듈의 모든 의존은 모듈 코드실행 전에 로드, 해석되고 연결 완료될 필요가 있고, import 를 통해 按需懶로드하는 구문은 존재하지 않음

  • import 모듈이 생성하는 오류에는 대응하는 회복 메커니즘이 없음. 어떤 모듈이 로드 또는 연결할 수 없는 경우, 모든 모듈은 실행되지 않고, import 오류를 캡처할 수 없음

  • 모듈이 의존을 로드하기 전에 다른 코드를 실행할 수 없고, 이는 모듈의 의존 로드 프로세스를 제어할 수 없음을 의미함

이러한 제한이 존재하므로, 아마도HTTP2 가 보급된 후에도, ES6 모듈 메커니즘은 여전히 브라우저에서 흥기할 수 없을 가능성이 있습니다. CSS 의 @import 처럼, 사용 가능하지만, 아무도 사용하고 싶어하지 않는 것과 같습니다

四.HTTP2 와 모듈화

HTTP1.1 의 환경 하에서는, HTTP 청구 수량을 감소시키기 위해, 모든 모듈화 방안은 최종적으로 빌드 도구에 의존하여 단일 파일을 통합합니다

하지만 HTTP2 는 몇 가지 변혁을 가져왔고, 아마도 이 엔지니어링 프로세스를 변경할 수 있을 가능성이 있습니다. 예를 들어 다로复用流(Multiplexed stream)와 서버端푸시:

Http2 연결은 수십 또는 수백의 流의复用을承载가능하고, 다로复用은 많은 流로부터의 데이터 패킷이 혼합되어 같은 연결을 통해传输될 수 있음을 의미하며, 2 열의 다른 기차가 혼합되어传输되고, 종점에 도달했을 때, 그것들은 또拆解되어 2 열의 다른 기차를組成합니다.

클라이언트가 리소스 X 를 청구하면, 서버端은 클라이언트가さらに리소스 Z 를 필요로 할 것이라고 판단하고, 사전에 클라이언트에게詢問할 필요 없이 리소스 Z 를 클라이언트에 푸시하고, 클라이언트는 받아들인 후, 캐시하여 후에 사용하기 위해备입니다.

Http 2.0 프로토콜简介 에서 발췌)

다로复用流는 파일 합병의 우위성을抹平하고, 서버端푸시는 깊이 import 문제를 해결하는 데 도움이 되므로, ES6 모듈은 브라우저 환경에서 흥기할 수 있을 가능성이 있습니다

HTTP2 는 모듈화 프로세스에 대해중요한 의미가 있고, 생산 환경에서 모듈화를 보유할 기회를 제공하며, JS, CSS 더욱이 다른 리소스도 진정한 모듈화를 맞이할 수 있을 가능성이 있습니다

P.S. HTTP2 의 더 많은 상세에 대해서는, https://github.com/bagder/http2-explained 참조

五.ES6 모듈 현황

As the various milestones of the roadmap are completed, browsers will be able to implement them. See the following trackers for the current status of the main browsers:

IE/Edge: Under Consideration

Firefox: In progress

Chrome: In progress

Webkit: Meta Bug

https://github.com/whatwg/loader 에서 발췌)

ES6 모듈 로더에 대한 더 많은 정보에 대해서는 이 repo 를关注하십시오. ES6 규범은 로드의 구체적 구현을 설명하지 않기 때문에, 브라우저는 모두 로더의 구현에서卡있습니다

참고 자료

  • 『ES6 in Depth』:InfoQ 中文站에서 제공하는 무료 전자책

댓글

아직 댓글이 없습니다

댓글 작성