웹 페이지의 구조가 점점 더 복잡해지고 있습니다. 여전히 모든 코드를 이전처럼 하나의 파일에 넣으면 다음과 같은 문제가 발생합니다. 🎜>
var module1 = new Object({ _count : 0, m1 : function (){ //... }, m2 : function (){ //... } });이것의 단점은 모듈의 모든 멤버가 노출된다는 것입니다! 함수의 로컬 변수는 외부에서 접근할 수 없다는 것을 알고 있으므로 즉시 실행 기능을 사용하여 최적화할 수 있습니다.
var module1 = (function(){ var _count = 0; var m1 = function(){ //... }; var m2 = function(){ //... }; return { m1 : m1, m2 : m2 }; })();누구나 특정 사양을 따를 수 있다면 다양한 방식으로 모듈을 정의할 수 있습니다. 이점은 매우 클 것입니다. 서로 참조할 수 있습니다! 모듈 사양math.js 모듈은 node.js에 다음과 같이 정의되어 있습니다.
function add(a, b){ return a + b; } exports.add = add;다른 모듈에서 사용할 경우 전역 require 함수를 사용하여 로드하면 됩니다. :
var math = require('math'); math.add(2,3);서버에서는 require 동기화에는 문제가 없으나, 네트워크 환경에서는 브라우저가 이를 할 수 없기 때문에 비동기식 AMD 사양이 있습니다:
require(['math'], function (math) {// require([module], callback); math.add(2, 3); });모듈은 다음과 같이 정의됩니다. 다음과 같습니다(모듈은 다른 모듈에 따라 달라질 수 있음):
define(function (){ // define([module], callback); var add = function (x,y){ return x+y; }; return { add: add }; });매우 훌륭하고 강력한 RequireJS(여기 참조)를 사용하면 다른 많은 리소스를 로드할 수 있습니다! 저는 직장에서 SeaJS를 더 자주 사용하는데, 사용되는 사양은 CMD라고 합니다. 권장합니다(비동기 모드 참조).
최대한 게으르게!종속 모듈 처리 방식과 AMD의 차이점은
AMD가 미리 실행되고(종속 항목이 앞에 있음), CMD가 지연되어 실행되는 것입니다. 방식(종속성이 근처에 있음).CMD에서 모듈을 정의하는 방법은 다음과 같습니다.
define(function(require, exports, module) { var a = require('./a'); a.doSomething(); var b = require('./b'); b.doSomething(); });사용방법은 문서를 직접 참고하시기 때문에 여기서는 자세히 다루지 않겠습니다! SeaJS 소스 코드 분석처음 모듈화를 접했을 때 너무 단순하다고 느꼈습니다.
onload를 설정하고 스크립트 태그를 생성할 때 src!실제로는 그렇긴 하지만 전부는 아닙니다! SeaJS 코드(sea-debug.js)부터 살펴보겠습니다. 모듈은 로드 프로세스 중에 다음 상태를 거칠 수 있습니다.
var STATUS = Module.STATUS = { // 1 - The `module.uri` is being fetched FETCHING: 1, // 2 - The meta data has been saved to cachedMods SAVED: 2, // 3 - The `module.dependencies` are being loaded LOADING: 3, // 4 - The module are ready to execute LOADED: 4, // 5 - The module is being executed EXECUTING: 5, // 6 - The `module.exports` is available EXECUTED: 6, // 7 - 404 ERROR: 7 }
개체는 모듈 정보를 유지하기 위해 메모리에서 사용됩니다. Modul
function Module(uri, deps) { this.uri = uri this.dependencies = deps || [] // 依赖模块ID列表 this.deps = {} // 依赖模块Module对象列表 this.status = 0 // 状态 this._entry = [] // 在模块加载完成之后需要调用callback的模块 }페이지에서 모듈 시스템을 시작하려면,
메소드: seajs.use
seajs.use(‘./main’, function(main) {// 依赖及回调方法 main.init(); });를 사용해야 합니다. 로딩 프로세스의 전체 로직은
: Module.prototype.load
Module.prototype.load = function() { var mod = this if (mod.status >= STATUS.LOADING) { return } mod.status = STATUS.LOADING var uris = mod.resolve() // 解析依赖模块的URL地址 emit("load", uris) for (var i = 0, len = uris.length; i < len; i++) { mod.deps[mod.dependencies[i]] = Module.get(uris[i])// 从缓存取或创建 } mod.pass(); // 将entry传递给依赖的但还没加载的模块 if (mod._entry.length) {// 本模块加载完成 mod.onload() return } var requestCache = {}; var m; // 加载依赖的模块 for (i = 0; i < len; i++) { m = cachedMods[uris[i]] if (m.status < STATUS.FETCHING) { m.fetch(requestCache) } else if (m.status === STATUS.SAVED) { m.load() } } for (var requestUri in requestCache) { if (requestCache.hasOwnProperty(requestUri)) { requestCache[requestUri]() } } }에서 볼 수 있습니다. 전체적인 로직은 매우 매끄러우므로 생략하겠습니다. 더 복잡한 것은
배열입니다. 인터넷에서 비교적 이해하기 쉬운 글을 찾을 수 없어서 코드를 보고 추측해봤는데 사실 그 목적만 기억하면 됩니다: _entry
모든 종속 모듈이 로드되면 콜백 함수를 실행하세요!즉,
array_entry는 현재 모듈이 로드된 후 로드될 수 있는 모듈 종속성의 목록을 저장합니다(종속성의 역관계) !예를 들어 모듈 A가 모듈 B, C, D에 종속되는 경우 통과 후 상태는 다음과 같습니다. At 이번에는
의 값이 3인데, 이는 아직 로드되지 않은 종속 모듈이 세 개 있다는 뜻입니다! 그리고 모듈 B가 모듈 E와 F에 의존하는 경우 A도 로드될 때 전달됩니다. remain
을 통해 모듈을 로드할 수 있습니다. :
importScriptsModule.prototype.fetch
sendRequest
메소드를 실행합니다. 결과를 바탕으로. 모든 종속 모듈이 로드된 후
메소드가 실행됩니다:Module.prototype.onload = function() { var mod = this mod.status = STATUS.LOADED for (var i = 0, len = (mod._entry || []).length; i < len; i++) { var entry = mod._entry[i] if (--entry.remain === 0) { entry.callback() } } delete mod._entry }
는 항목에 해당하는 모듈에 종속성 목록 중 하나가 이미 완료되었음을 알리는 것과 같습니다! 그리고 load
은 의존하는 모든 모듈이 로드되었음을 의미합니다! 그러면 이때 콜백 함수가 실행됩니다: error
for (var i = 0, len = uris.length; i < len; i++) { exports[i] = cachedMods[uris[i]].exec(); } if (callback) { callback.apply(global, exports)// 执行回调函数 }
onload
스크립트가 다운로드된 후 모듈 정보를 유지하기 위해 메서드가 즉시 실행됩니다. --entry.remain
entry.remain === 0
은 종속성이 명시적으로 지정되지 않은 경우 사용됩니다.parseDependency는 일반 일치 메서드에서 require() 조각을 사용합니다(종속성 목록을 지정하는 것이 좋습니다).
define
그런 다음
var exports = isFunction(factory) ? factory.call(mod.exports = {}, require, mod.exports, mod) : factory然后执行你在seajs.use中定义的
callback
方法:if (callback) { callback.apply(global, exports) }当你写的模块代码中require时,每次都会执行factory方法:
function require(id) { var m = mod.deps[id] || Module.get(require.resolve(id)) if (m.status == STATUS.ERROR) { throw new Error('module was broken: ' + m.uri) } return m.exec() }到这里核心的逻辑基本上讲完了,补一张状态的转换图:
以后在用的时候就可以解释一些诡异的问题了!
总结
模块化非常好用,因此在ECMAScript 6中也开始支持,但是浏览器支持还是比较堪忧的~~
위 내용은 JavaScript 모듈화 및 SeaJs 소스 코드 분석에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!