jsモジュールロードの詳細
9758 ワード
Javaの中の様々なimportロードを見て、振り返ってみるとjavascriptはまだ自分で車輪を作っていて、いろいろなXXのモジュールロードフレームワークを書いていて、ECMASCRIPT 6はいつ普及するか分かりません.しかし、DTはDTに戻り、学ぶべきことはやはり学ばなければならない.
同期ロードモード(SMD)
同期は、名前の通り、AモジュールがBモジュールのいくつかの関数を参照して実行するなど、順次ロードされます.この場合、Bモジュールはすでにページメモリに存在している必要があります.A呼び出しは、次の操作を順調に完了します.例は、ブラウザメモリにすでに存在するため、Aモジュールがdocumentオブジェクトを直接呼び出すことです.
同期モジュールコードの実現も比較的に簡単で、モジュールの経路を解析して、実行は関数を落として、モジュールを呼び出します
モジュールの定義
上のコードでは、defineとmoduleはそれぞれモジュールの定義と呼び出しであり、モジュールは閉パッケージFに定義され、getF()呼び出しによって呼び出されます.ここでoldとparentの2つのオブジェクトが使用されているのは、現在のモジュールの親モジュールと祖父モジュールのキャッシュを保存するためであり、モジュールブロックを順次追加した後、現在のモジュールにコールバック関数を実行するためです.
ここでのコールバック関数は、jsファイルに書かれるモジュールの構築についてです.例えば、次のコードには、構造関数と静的メソッドが含まれています.
モジュールを呼び出す
モジュールオブジェクトをコールバック関数に導入してモジュールの呼び出しを実行するには、モジュールパスを解析し、ロードするモジュールをmodules配列に入れて実現することが重要です.例は以下の通り
デュアル非同期ロードモード
前言
上記の同期ロードモードから見ると、モジュールはメモリにロードされ始め、scriptラベルを非同期でバインドしてモジュールをロードしていません.では、他の人が書き終わっていないjsモジュールファイルをどのように参照するかという問題が発生し、非同期ロードの問題が発生しました.現在、各モジュールのロードフレームワークはこのように行われています.
セット定義と呼び出しを一体化したモジュールローダ
上のコードで重要なのは、iを保存するために閉パッケージを使用することです.閉パッケージを使用しない場合、iの値は、毎回の結果ではなく、モジュールの数に最後に依存するだけです.閉鎖問題については私のブログを見ることができます.
コードに使われている2つの重要な関数はloadModuleとsetModuleです.以下、この2つのコードについて説明します.
loadModule関数がモジュールをロードする場合は3つに分けられます.コード注釈にも書いてあります.肝心なのは、jsモジュールでjsファイルの状態が「loaded」であればすぐにcallbackコールバック関数を実行することです.ここでsettimeoutを0ミリ秒に遅延させる役割は、必ずしもすぐに実行するのではなく、次のtrickまで待って実行します.フロントエンドでは、すぐに実行されると理解され、callback関数は、モジュールを作成するときに関数returnのオブジェクトを指すモジュールの外部インタフェースを彼に渡します.
F.moduleでは、依存モジュールがメモリにロードされている場合にのみsetModuleを使用してモジュールを修正します.この関数は、モジュール属性(moduleName,status,exports,onload)をロード完了後の状態に修正し、コールバック関数を実行する役割を果たします.ここで実行されるコールバック関数は、loadModuleが実行するコールバック関数とは異なり、loadModuleは依存モジュールを実行するためのドロップダウンであり、ここでは最終モジュールを実行するコールバックである.
これにより、完全なモジュールローダが実現され、上記の非同期ローダはRequireJSに類似している.依存に関する場合は事前に定義され、定義されるとロードされなければならず、近接宣言の原則に合致しないため、最適化されるべき場所であり、批判の指摘も望ましい.
同期ロードモード(SMD)
同期は、名前の通り、AモジュールがBモジュールのいくつかの関数を参照して実行するなど、順次ロードされます.この場合、Bモジュールはすでにページメモリに存在している必要があります.A呼び出しは、次の操作を順調に完了します.例は、ブラウザメモリにすでに存在するため、Aモジュールがdocumentオブジェクトを直接呼び出すことです.
同期モジュールコードの実現も比較的に簡単で、モジュールの経路を解析して、実行は関数を落として、モジュールを呼び出します
モジュールの定義
var manger = (function(){ var F = F || {}; F.define = function(str, fn){ var parts = str.split('.'), old = parent = this,//old ,parent i = len = 0; for(len = parts.length; i < len; i++){ if(typeof parent[parts[i]] === 'undefined'){ parent[parts[i]] = {}; } old = parent; parent = parent[parts[i]]; } if(fn){ old[parts[--i]] = fn(); } return F; } })();
上のコードでは、defineとmoduleはそれぞれモジュールの定義と呼び出しであり、モジュールは閉パッケージFに定義され、getF()呼び出しによって呼び出されます.ここでoldとparentの2つのオブジェクトが使用されているのは、現在のモジュールの親モジュールと祖父モジュールのキャッシュを保存するためであり、モジュールブロックを順次追加した後、現在のモジュールにコールバック関数を実行するためです.
ここでのコールバック関数は、jsファイルに書かれるモジュールの構築についてです.例えば、次のコードには、構造関数と静的メソッドが含まれています.
manger.getF().define('dom', function(){ var dom = function(id){ return document.getElementById(id); } dom.html = function(html){ return this.innerHTML; } return dom; });
モジュールを呼び出す
F.module = function(mod,callback){ var args = [].slice.call(arguments), fn = args.pop(), parts = args[0] && args[0] instanceof Array?args[0]:args, modules = [], modIds = '', i = 0, ilen = parts.length, parent, j, jlen; while(i < ilen){ if(typeof parts[i] === 'string'){ parent = this;//this
modIds = parts[i].replace('/^F\./', '').split('.');//modIds=[]
for(j = 0, jlen = modIds.length; j < jlen; j++){ parent = parent[modIds[j]] || false; } modules.push(parent);// modules ,
}else{ modules.push(parts[i]); } i++; } fn.apply(null, modules); }
モジュールオブジェクトをコールバック関数に導入してモジュールの呼び出しを実行するには、モジュールパスを解析し、ロードするモジュールをmodules配列に入れて実現することが重要です.例は以下の通り
manger.getF().module(['dom'],function(dom){ dom('div1'); });
デュアル非同期ロードモード
前言
上記の同期ロードモードから見ると、モジュールはメモリにロードされ始め、scriptラベルを非同期でバインドしてモジュールをロードしていません.では、他の人が書き終わっていないjsモジュールファイルをどのように参照するかという問題が発生し、非同期ロードの問題が発生しました.現在、各モジュールのロードフレームワークはこのように行われています.
セット定義と呼び出しを一体化したモジュールローダ
F.module = function(url, modDeps, modCallback){
var args = [].slice.call(arguments);
var callback = args.pop();
var deps = (args.length && (args[args.length - 1] instanceof Array)) ? args
.pop() : [];
var url = args.length ? args.pop() : null,
params = [], // , ,
depsCount = 0, //
i = 0;//
var len;
if (len = deps.length) {
while(i<len){//
(function(i){// , , setModule
depsCount++;
loadModule(deps[i],function(mod){
params[i] = mod;// params【i】
depsCount--;
if(depsCount===0){// ,
setModule(url,params,callback);
}
});
})(i);
/*depsCount++;
loadModule(deps[i],function(mod){
params[i] = mod;// params【i】
depsCount--;
if(depsCount===0){// ,
setModule(url,params,callback);
}
});*/
i++;
}
}else{// ,
setModule(url,[],callback);//setModule('lib/event',[],fn)
}
}
上のコードで重要なのは、iを保存するために閉パッケージを使用することです.閉パッケージを使用しない場合、iの値は、毎回の結果ではなく、モジュールの数に最後に依存するだけです.閉鎖問題については私のブログを見ることができます.
コードに使われている2つの重要な関数はloadModuleとsetModuleです.以下、この2つのコードについて説明します.
loadModule = function(name, callback){
var module;
if (moduleCache[name]) {//
_module = moduleCache[name];
if (_module.status = 'loaded') {//
// , , params[i]
setTimeout(callback(_module.exports), 0);
} else {// , , onload ,
_module.onload.push(callback);
}
} else {// , ,onload , ,
moduleCache[name] = {
name : name,
status : 'loading',
exports : null,
onload : [ callback ]
};
loadScript(getUrl(name));// js
}
for ( var i in moduleCache) {
console.log(moduleCache[i]);
}
};
loadModule関数がモジュールをロードする場合は3つに分けられます.コード注釈にも書いてあります.肝心なのは、jsモジュールでjsファイルの状態が「loaded」であればすぐにcallbackコールバック関数を実行することです.ここでsettimeoutを0ミリ秒に遅延させる役割は、必ずしもすぐに実行するのではなく、次のtrickまで待って実行します.フロントエンドでは、すぐに実行されると理解され、callback関数は、モジュールを作成するときに関数returnのオブジェクトを指すモジュールの外部インタフェースを彼に渡します.
// js , js ,params ,
setModule = function(name, params, callback){
var _module, fn;
if (moduleCache[name]) {// ( ) , js
_module = moduleCache[name];
_module.status = 'loaded';
_module.exports = callback ? callback.apply(_module, params) : null;//exports
while (fn = _module.onload.shift()) {
console.log(' :'+fn);
console.log(' :'+_module.exports);
for(var i in _module.exports){
console.log(i);
}
fn(_module.exports);
}
} else {// , ,
console.log(' :'+callback);
for(var i in params){
console.log(' '+i+':'+params[i]);
if(typeof params[i]==='object'){
for(var j in params[i]){
console.log(j+':'+params[i][j]);
}
}
}
callback && callback.apply(null, params);
}
},
F.moduleでは、依存モジュールがメモリにロードされている場合にのみsetModuleを使用してモジュールを修正します.この関数は、モジュール属性(moduleName,status,exports,onload)をロード完了後の状態に修正し、コールバック関数を実行する役割を果たします.ここで実行されるコールバック関数は、loadModuleが実行するコールバック関数とは異なり、loadModuleは依存モジュールを実行するためのドロップダウンであり、ここでは最終モジュールを実行するコールバックである.
これにより、完全なモジュールローダが実現され、上記の非同期ローダはRequireJSに類似している.依存に関する場合は事前に定義され、定義されるとロードされなければならず、近接宣言の原則に合致しないため、最適化されるべき場所であり、批判の指摘も望ましい.