머리말
여기에 모듈 온다!
사이트는 "인터넷 응용 프로그램"점점 더 크고 더 복잡한 웹 페이지에 포함 된 자바 스크립트 코드가되기로. 웹이 더 데스크톱 프로그램처럼, 당신은 노동, 일정 관리, 단위 테스트 부문의 팀이 필요합니다 ...... 우리는 페이지의 비즈니스 로직을 관리하는 데 사용하는 소프트웨어 엔지니어링 방법에 있습니다.
그래서, 자바 스크립트 모듈 긴급한 필요. ES6 모듈의 출현은, 자바 스크립트는 강력한 커뮤니티 지원을 제공하기 전에, 모듈의 효과를 달성하기 위해 기존 운영 환경에서 시도합니다.
CommonJS 및 노드
자바 스크립트 : 그냥 브라우저에 어떤 이상! - CommonJS Slogen
사실상의 표준 프런트 엔드 모듈 중 하나는, 2009 년 8 월, CommonJS는 출생.
CommonJS 본질적으로 단지 규격 (API 정의) 및 규격의 Node.js를 구현 부분 사용에 대한 문구 CommonJS으로 Module1 때문에 광범위한.
노드의 구현을 살펴 보자 :
1
2
3
4
5
6
7
8
9
// 由于 Node 原生支持模块的作用域,并不需要额外的 wrapper
// "as though the module was wrapped in a function"
var a = require('./a') // 加载模块(同步加载)
a.doSomething() // 等上一句执行完才会执行
exports.b = function(){ // 暴露 b 函数接口
// do something
}
exports
a는 내장되어 객체처럼 require
내장로드 기능 같은. 직접 할당 할 경우 완전한 객체 또는 생성자는 오버라이드 (override) module.exports
를.
CommonJS는 이전에, ServerJS라는 환경의 표준화 모듈 테이크 모든 다양한 이름 CommonJS, 다음보다 일반적인 될 기대 될 . CommonJS 처음보다는 브라우저 환경보다 서버 측에 초점을 맞추고, 그 서버 환경 (디스크 I / O를 속도)는 문제가되지는 동기식로드 메커니즘을 사용하지만 브라우저 환경 (망 속도) 아니다 적절한.
따라서, 모듈 형 프레임 워크와 표준에 의해 출생에 적합, 그들은 공통적으로 가지고있는 다양한 브라우저 환경은 다음과 같습니다 :
- 비동기 로딩 (네트워크 환경 브라우저 모든 종속 모듈의 실행 후 사전로드 콜백)
- 다른 코딩 스타일이지만, 그러나 사실은 변형 CommonJS 모듈 구문으로 볼 수있다.
- 우리를 향해있는 공통의 진화의 방향 : 다른 스타일 호환 브라우저와 서버 환경 모두와 호환
통상적 인 실시 예는 여기 설명 된 다음에 설명한다 :
- RequireJS 및 AMD (비동기 로딩, - 실행을 사전에 미리 기본에 의존하는이 문구 AMD를 권장)
- SeaJS & CMD (비동기 로딩, 게으른 실행, 근처에 의존하고, 기본 추천 CommonJS 문구)
역사
유 보의에서이 항 참조 그 시점에 프런트 엔드 모듈 개발 역사
09~10년 사이 CommonJS (다음 여전히라고 ServerJS) 지역 사회가 시작 모듈 / 1.0 사양을하고 Node.js를 환경에 아주 좋은 연습을했다.
커뮤니티 CommonJS에 자신의 이름을 변경할 수 있도록 또한, 브라우저에 성공적인 경험을 촉진 ServerJS하려고하는 사람의 2,009 동기 무리의 두 번째 절반 사양의 다음 버전의 동안 열띤 논쟁 모듈. 차이와 충돌이 태어 났으며, 점차적으로 세 가지 주요 학교를 형성 :
- 모듈 / 1.x의 장르. 방금 잘 브라우저에 이식만큼, 충분한되었습니다이보기 1.x의 사양. 추가되는 수행 모듈 / 전송 전송 모듈 사양에 맞춰 코드를 변환하는 제 1 변환 도구, 브라우저에서 실행하기 전에, 인 규범을. 주류 대표는 서버 측 개발자입니다. 점점 더 많은 화재 구성 요소 및 ES6 모듈 transpiler의 최전선 : 지금이 달성 주목할있다.
- 모듈 / 비동기 장르. 이보기는 브라우저 자체의 특성을 가지고, 모듈 / 1.x의 사양을 사용할 수 없습니다. 이보기의 전형적인 대표 아래 AMD의 규격과 그 구현 RequireJS는 . 이것은 나중에 자세히 설명.
- 모듈 / 2.0 장르. 이보기는 브라우저 자체의 특성을 가지고, 모듈 / 1.x의 사양을 사용하지 말아야하지만, 가능한 모듈 / 1.x의 사양과 일치해야합니다. 이보기의 전형적인 대표 아래 BravoJS 및 FlyScript의 저자이다. 지역 사회에 큰 기여 BravoJS CommonJS,이 모듈 / 2.0 초안 스펙은 생각을 많이 보냈다. FlyScript의 저자는 CMD의 전신 사양을 표준화 모듈 / 배치와 사양을 제안했다. 불행하게도 BravoJS 너무 학문적, FlyScript 나중에 조립 라인 오프 셀프 거세, 전체 사이트 (flyscript.org)가되었다. 이 문서에서이보기의 전형적인 대표 SeaJS와 CMD입니다
입 메이크업 : AMD가 매우 유사하지만,와 함께, KMD의 사실을 알리 뽀뽀를 add
하고 use
기능 YUI 모듈의 이름에서 파생 된 두 개의 교체 define
와 require
의 가까운 RequireJS을하지만, 원칙이며, YUI 모듈 Y
샌드 박스에 연결 메커니즘은 동일하지 않습니다
RequireJS 및 AMD
AMD (비동기 모듈 정의) 승격 프로세스 모듈 정의 정규화 출력 RequireJS이다.
RequireJS는 자바 스크립트 파일과 모듈 로더입니다. 그것은에서 브라우저에 최적화되어 있지만, 다른 자바 스크립트 환경에서 사용할 수 있습니다
주요 문제는 여전히 브라우저이 질문에 맞지 않는 동기로드 스크립트를 CommonJS RequireJS :
1
2
3
4
5
6
7
8
9
10
11
12
//CommonJS
var Employee = require("types/Employee");
function Programmer (){
//do something
}
Programmer.prototype = new Employee();
//如果 require call 是异步的,那么肯定 error
//因为在执行这句前 Employee 模块肯定来不及加载进来
주석 위에서 알 수 있듯이, 경우는이 코드는하지 않습니다 일, () 비동기입니다 필요합니다. 그러나, 브라우저에서 동 기적으로 스크립트를로드하면 성능을 죽인다. 그래서 뭐 할까?
우리가 필요 그래서 포장을 함수 출세와 사전에 스크립트 태그를 통해 부하에 따라하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//AMD Wrapper
define(
[types/Employee], //依赖
function(Employee){ //这个回调会在所有依赖都被加载后才执行
function Programmer(){
//do something
};
Programmer.prototype = new Employee();
return Programmer; //return Constructor
}
)
모듈이 매우 오랜 시간이 의존하는 경우,이 의존 사전에 AMD는 문법 설탕, 주신 있도록 표현은, 홀수 조금 보인다 간체 CommonJS 포장이 CommonJS에 대해서도 더 편리 CommonJS 가장 가까운 스타일을 필요에 그리기, 호환 모듈,하지만를 :
1
2
3
4
5
6
define(function (require) {
var dependency1 = require('dependency1'),
dependency2 = require('dependency2');
return function () {};
});
AMD의 로더는 구문 분석됩니다 require('')
사용하여 통화를 Function.prototype.toString()
한 후 내부적으로 위의 정의 호출 변환 :
1
2
3
4
5
6
define(['require', 'dependency1', 'dependency2'], function (require) {
var dependency1 = require('dependency1'),
dependency2 = require('dependency2');
return function () 大专栏 JavaScript Module Loader - 李林的博客{};
});
대한 Function.prototype.toString()
호환성과 성능을 고려하여, 가장 좋은 방법은하는 것입니다 최적화 된 빌드
AMD와 CommonJS 핵심 분쟁은 다음과 같습니다 :
1. 执行时机
Modules/1.0:
1
var a = require("./a") // 执行到此时,a.js 才同步下载并执行
AMD: (使用 require 的语法糖时)
1
2
3
4
5
define(["require"],function(require)){
// 在这里,a.js 已经下载并且执行好了
// 使用 require() 并不是 AMD 的推荐写法
var a = require("./a") // 此处仅仅是取模块 a 的 exports
})
AMD 里提前下载 a.js 是出于对浏览器环境的考虑,只能采取异步下载,这个社区都认可(Sea.js 也是这么做的)
但是 AMD 的执行是 Early Executing,而 Modules/1.0 是第一次 require 时才执行。这个差异很多人不能接受,包括持 Modules/2.0 观点的人也不能接受。
2. 书写风格
AMD 推荐的风格并不使用require
,而是通过参数传入,破坏了依赖就近:
1
2
3
4
5
define(["a", "b", "c"],function(a, b, c){
// 提前申明了并初始化了所有模块
true || b.foo(); //即便根本没用到模块 b,但 b 还是提前执行了。
})
不过,在笔者看来,风格喜好因人而异,主要还是预执行和懒执行的差异。
另外,require 2.0 也开始思考异步处理软依赖(区别于一定需要的硬依赖)的问题,提出了这样的方案:
1
2
3
4
5
6
// 函数体内:
if(status){
async(['a'],function(a){
a.doSomething()
})
}
SeaJS & CMD
CMD (Common Module Definition) 是 SeaJS 在推广过程中对模块定义的规范化产出,是 Modules/2.0 流派的支持者,因此 SeaJS 的模块写法尽可能与 Modules/1.x 规范保持一致。
不过目前国外的该流派都死得差不多了,RequireJS 目前成为浏览器端模块的事实标准,国内最有名气的就是玉伯的 Sea.js ,不过对国际的推广力度不够。
- CMD Specification
CMD 主要有 define, factory, require, export 这么几个东西
- define
define(id?, deps?, factory)
- factory
factory(require, exports, module)
- require
require(id)
- exports
Object
CMD 推荐的 Code Style 是使用 CommonJS 风格的 require
:
- 这个 require 实际上是一个全局函数,用于加载模块,这里实际就是传入而已
1
2
3
4
5
6
7
8
9
10
11
12
13
define(function(require, exports) {
// 获取模块 a 的接口
var a = require('./a');
// 调用模块 a 的方法
a.doSomething();
// 对外提供 foo 属性
exports.foo = 'bar';
// 对外提供 doSomething 方法
exports.doSomething = function() {};
});
但是你也可以使用 AMD 风格,或者使用 return 来进行模块暴露
1
2
3
4
5
6
7
8
9
10
11
define('hello', ['jquery'], function(require, exports, module) {
// 模块代码...
// 直接通过 return 暴露接口
return {
foo: 'bar',
doSomething: function() {}
};
});
Sea.js 借鉴了 RequireJS 的不少东西,比如将 FlyScript 中的 module.declare 改名为 define 等。Sea.js 更多地来自 Modules/2.0 的观点,但尽可能去掉了学院派的东西,加入了不少实战派的理念。
AMD vs CMD
虽然两者目前都兼容各种风格,但其底层原理并不相同,从其分别推荐的写法就可以看出两者背后原理的不同:
- 对于依赖的模块,AMD 是提前执行,CMD 是懒执行。(都是先加载)
- CMD 推崇依赖就近,AMD 推崇依赖前置。
看代码:
1
2
3
4
5
6
7
8
9
// AMD 默认推荐
define(['./a', './b'], function(a, b) { // 依赖前置,提前执行
a.doSomething()
b.doSomething()
})
1
2
3
4
5
6
7
8
9
10
// CMD
define(function(require, exports, module) {
var a = require('./a')
a.doSomething()
var b = require('./b') // 依赖就近,延迟执行
b.doSomething()
})
WebPack
working…