モジュールの読み込みは、実際にJSを多くのモジュールに分割して、簡単に開発とメンテナンスします。したがって、多くのJSモジュールをロードするときは、ユーザーエクスペリエンスを改善するために動的にロードする必要があります。
モジュールロードライブラリを導入する前に、メソッドを紹介します。
JSメソッドの動的荷重:
コードコピーは次のとおりです。
function loadjs(url、callback){
var node = document.createelement( "script");
node [window.addeventlistener? 「onload」:「onreadystatechange "] = function(){
if(window.addeventlistener || /loaded|complete/i.test(node.readystate)){
折り返し電話();
node.oneadystatechange = null;
}
}
node.onerror = function(){};
node.src = url;
var head = document.getElementsByTagname( "head")[0];
head.insertbefore(node、head.firstchild); //ヘッドの最初のノードに挿入する前に、IE6の下のヘッドタグが閉じられないようにし、appendChildを使用してエラーを報告します。
}
situ zhengmeiは、モジュールの負荷を導入するために書いたマスフレームワークを使用したため、業界で最も使用されているのはrequire.jsとsea.jsです。したがって、彼は強い性格を持っていると思います。
Sea.jsの負荷プロセスについて話させてください:
Page Chaosan.jsはヘッドタグに導入され、Seajsオブジェクトが取得されます。
index.jsも紹介します。
index.jsのコードは次のとおりです。
コードコピーは次のとおりです。
seajs.use(['./ a'、 'jquery']、function(a、$){
var num = aa;
$( '#j_a')。text(num);
})
A.JS:
コードコピーは次のとおりです。
定義(関数(要求、エクスポート、モジュール){
var b = require( './ b');
var a = function(){
1 + parseint(bb())を返します。
}
exports.a = a;
})
B.JS:
コードコピーは次のとおりです。
定義(関数(要求、エクスポート、モジュール){
var c = require( './ c');
var b = function(){
2 + parseint(cc())を返します。
}
exports.b = b;
})
C.JS:
コードコピーは次のとおりです。
定義(関数(要求、エクスポート、モジュール){
var c = function(){
3を返します。
}
exports.c = c;
})
上記から、モジュールaはbに依存し、bはcに依存することがわかります。
プログラムがindex.jsに入ると、Seajsは使用方法を呼び出します。
コードコピーは次のとおりです。
seajs.use = function(ids、callback){
GlobalModule._use(ids、callback)
}
説明:GlobalModuleがSEAJSで初期化されている場合(SEA.JSが導入されたとき)、Module var GlobalModule = new Module(util.pageuri、status.compiled)のインスタンス
この時点でids-> ['./a'、' jquery ']、callback-> function(a、$){var num = aa; $('#j_a ')。text(num);}
次に、GlobalModule._use(ids、callback)が呼び出されます
コードコピーは次のとおりです。
module.prototype._use = function(ids、callback){
var uris = Resolve(ids、this.uri); //解像度['./a'、'Jquery']
this._load(uris、function(){//解析されたaおよびjqueryモジュール[url1、url2]のアドレスを呼び出し、_loadメソッドを呼び出します。
//util.map:すべてのデータメンバーに指定された関数を一度に実行し、元の配列メンバーのコールバック実行の結果である新しい配列を返します
var args = util.map(uris、function(uri){
uriを返しますか? cachedmodules [uri] ._ compile():null; // urlが存在する場合、_compileメソッドを呼び出します。
})
if(callback){callback.apply(null、args)}
})
}
_loadメソッドを呼び出した後、2つのコールバック関数が表示されるため、関数(a、$){var num = aa; $( '#j_a')。
this._load(uris、function(){})callbackメソッドフラグをcallback2に設定します。
Resolveメソッドはモジュールアドレスを解決することであるため、ここで詳しく説明しません。
最後に、var uris = resolve(ids、this.uri)のurisは['http://localhost/test/seajs/a.js'、'http://localhost/test/seajs/lib/juqery/1.7.2/posed exmilt.js]に分類されました。
次にthis._loadが実行されます
コードコピーは次のとおりです。
// _load()メソッドは、最初にまだ準備ができていないリソースファイルを決定します。すべてのリソースファイルが対応の状態にある場合、CallBack2が実行されます。
//この場合、円形の依存関係を作成し、無負荷のJSにロードを実行します
module.prototype._load = function(uris、callback2){
//util.filter:すべてのデータメンバーが一度に指定された関数を実行して、新しい配列を返すようにします。配列は、元の配列メンバーからコールバックを実行した後にtrueを返すメンバーです。
// unloadedurisは、コンパイルされていないモジュールの配列です
var unloadeduris = util.filter(uris、function(uri){
//実行機能ブール値が真であるか、URIが存在し、内部変数カチューモジュールに存在しない場合に真が返されるか、ステータスの値を保存します。
// Status.ready値が4の場合、4未満の場合、取得およびダウンロードされている可能性があります。
uri &&(!cachedmodules [uri] ||を返します
cachedmodules [uri] .status <status.ready)
});
// urisのすべてのモジュールの準備ができた場合、コールバックを実行して関数本体を終了します(今回はモジュールの_compileメソッドが呼び出されます)。
var length = unloadeduris.length
if(length === 0){callback2()return}
//ロードされていないモジュールの数
varは=長さです
//クロージャーを作成し、ロードされていないモジュールをロードしてみてください
for(var i = 0; i <length; i ++){
(function(uri){
// URIストレージ情報が内部変数Cachedmodulesに存在しない場合は、モジュールオブジェクトをインスタンス化します
var module = cachedmodules [uri] ||
(cachedmodules [uri] = new Module(URI、Status.Fetching))
//モジュールの状態値が2以上の場合、モジュールがダウンロードされ、すでにローカルに存在していることを意味します。この時点で、onfetched()が実行されます
//それ以外の場合、Fetch(URI、OnFetched)が呼び出され、リソースファイルをダウンロードしようとします。リソースファイルがダウンロードされた後、オンロードはトリガーされ、オンロードでオンフェッチされたメソッドが実行されます。
module.status> = status.fetched? onfetched():fetch(uri、onfetched)
function onfetched(){
モジュール= cachedmodules [uri]
//モジュールの状態値がstatus.saved以上である場合、モジュールのすべての依存関係情報が取得されていることを意味します
if(module.status> = status.saved){
// getPeardEpendencies:円形の依存関係なしで依存関係配列を取得します
var deps = getpeardependencies(モジュール)
//依存関係配列が空でない場合
if(deps.length){
//すべての依存関係がロードされ、すべての依存関係の読み込みが完了した後にすべての依存関係がロードされ、コールバックが実行されるまで_load()メソッドを再度実行します
module.prototype._load(deps、function(){
CB(モジュール)
})
}
//依存関係配列が空の場合は、CB(モジュール)を直接実行します
それ以外 {
CB(モジュール)
}
}
// 404などの買収が失敗した場合、またはモジュラー仕様に準拠していない場合
//この場合、module.Statusはフェッチまたはフェッチで維持されます
それ以外 {
cb()
}
}
})(unloadeduris [i])
}
// CBメソッド - すべてのモジュールを読み込んだ後にコールバックを実行する
関数CB(モジュール){
//モジュールのストレージ情報が存在する場合は、モジュールストレージ情報のステータス値を変更し、ステータスの準備に変更します。
モジュール&&(module.status = status.ready)
//コールバックは、すべてのモジュールがロードされている場合にのみ実行されます。
-remain === 0 && callback2()
}
}
}
ここでは、Unloadedurisの配列の長さは2、['http://localhost/test/seajs/a.js'、'http://localhost/test/seajs/lib/1.7.2/juqery-debug.js']、次の2つの閉鎖は次のようになります。
例としてhttp://localhost/test/seajs/a.jsを使用してください
次:最初に、モジュールが作成されます。
コードコピーは次のとおりです。
cachedmodules( 'http://localhost/test/seajs/a.js')= new Module( 'http://localhost/test/seajs/a.js',1)
module.status> = status.fetched? onfetched():fetch(uri、onfetched)
モジュールAは現時点ではロードされていないため、フェッチ(URI、オンフェッチ)が次に実行されます。つまり、Fetch( 'http://localhost/test/seajs/a.js', oonfetched)です。
コードコピーは次のとおりです。
function fetch(uri、onfetched){
//マップのルールに従ってURIを新しいリクエストアドレスに置き換えます
var requesturi = util.parsemap(uri)
//最初に、requesturiレコードが取得したリストに含まれているかどうかを調べます
if(fetchedList [requesturi]){
//この時点で、元のURIのモジュールストレージ情報をMAPで再定義したRequesturiに更新します
cachedmodules [uri] = cachedmodules [requesturi]
// onefetchedと戻りを実行すると、モジュールが正常に取得されたことを意味します
onfetched()
戻る
}
//取得リストのrequesturiのストレージ情報をクエリします
if(fetchinglist [requesturi]){
// callbackListのURIに対応するコールバックを追加して返します
callbacklist [requesturi] .push(onfetched)//取得している場合は、このモジュールの漏れたコールバックメソッドを配列に押して返します。
戻る
}
//取得しようとしているモジュールがfetchedListとfetchingListに表示されない場合は、それぞれリクエストリストとコールバックリストに情報を追加します
fetchinglist [requesturi] = true
callbacklist [requesturi] = [onfetched]
//それを取得します
module._fetch(
requesturi、
関数() {
fetchedList [requesturi] = true
//モジュールステータスを更新します
// module.statusがstatus.fectchingに等しい場合、モジュールステータスを取得するに変更します
var module = cachedmodules [uri]
if(module.status === status.fetching){
module.status = status.fetched
}
if(fetchinglist [requesturi]){
fetchinglist [requesturi]を削除する
}
//コールバックのcallbackList Unified実行を呼び出します
if(callbacklist [requesturi]){
util.foreach(callbacklist [requesturi]、function(fn){
fn()// fnは、モジュールaに対応するオンフェッチメソッドです。
})
callbacklist [requesturi]を削除する
}
}、
config.charset
))
}
次に、module._fetch()が実行され、ここでコールバック関数をCallback3と呼びます。
この方法は、loadjsメソッドを呼び出して、A.JSファイルを動的にダウンロードします。 (AとjQueryがあるため、2つの新しいスクリプトが作成されます)。ここに質問があります。 Aのスクリプトを作成してヘッドに追加すると、JSファイルをダウンロードします。ただし、Seajsではダウンロードされていません。代わりに、jQueryのスクリプトが確立されるまで待機し、それをダウンロードする前に頭に追加されます(Googleデバッガーはブレークポイントを設定し、待ち待っていることを示し続けます)。これは毛沢東のためですか?
(ここで推奨:http://ux.sohu.com/topics/50972d9ae7de3e752e0081ff。ここでは追加の質問についてお話します。テーブルを使用するためにテーブルを使用する必要がある理由を知っているかもしれません。表示される前に、検証後にDivが表示されます。
ダウンロードが成功した後、解析および実行され、定義メソッドが実行されます。ここでは、最初にモジュールaのコードを実行します。
定義(id、deps、function(){})メソッド分析
コードコピーは次のとおりです。
//定義、ID:モジュールID、DEPS:モジュール依存関係、ファクトリー
module._define = function(id、deps、factory){
//依存関係を解決する// depsが配列タイプでない場合、工場は関数です
if(!util.isarray(deps)&& util.isfunction(factory)){//関数本体は定期的に文字列に一致し、配列を形成してdepsへの割り当てを返すために配列を形成します
deps = util.parsedependencies(factory.tostring())
}
//メタ情報を設定します
var meta = {id:id、依存関係:deps、工場:工場}
if(document.attachevent){
//現在のスクリプトのノードを取得します
var script = util.getCurrentscript()
//スクリプトノードが存在する場合
if(script){
//元のURIアドレスを取得します
deriveduri = util.unparsemap(util.getscriptabsolutesrc(script))}
if(!deriveduri){
util.log( ''、factory.tostring()、 'Warn'のインタラクティブスクリプトからURIを導き出せなかった)
}
}
.........
}
定義は、最初に工場で判断を下し、それが関数であるかどうかを判断します(その理由は、定義にもファイルとオブジェクトを含めることができるためです)
それが関数の場合、関数はFactory.toString()を介して取得され、A.JSの依存関係は定期的に一致し、DEPSで依存関係が保存されます
A.JSの場合、その依存関係はb.jsなので、depsは['./B']です
a.js var meta = {id:id、依存関係:Deps、Factory:Factory}の情報を保存}
a.js meta = {id:undefined、依存関係:['./b']、Factory:function(xxx){xxx}}
IE 6-9ブラウザでは、JSを実行するパスを取得できます。ただし、標準のブラウザでは、これは実行可能ではないため、Meta情報をAnonymousModuleMeta = Metaに割り当てることができます。
次に、オンロードをトリガーすると、コールバックメソッドCallBack3が呼び出されます。このコールバックメソッドは、現在のコールバックモジュール(A.JS)のステータス値を変更し、モジュールに設定します。Status= status.fetched。
次に、コールバックキューコールバックリストのA.JSに対応するコールバックは、均一に実行されます。
漏れたメソッドは、モジュールAに従属モジュールがあるかどうかをチェックします。 aはbに依存するため、b.jsで_load()を実行するモジュールaが依存します。
Bモジュールがダウンロードされ、jQuery定義方法が最初に実行されます。 jqueryは、オンロードコールバック後、モジュールに依存していないためです。オンフェッチした呼び出しCBメソッド。
Aと同じプロセスでBが実装されると、モジュールCがダウンロードされます。最後に、C、B、Aモジュールがダウンロードされて実行され、オンロードが完了した後、CBメソッドも呼び出されます(最初はC、次にB、次にC)
すべてのモジュールの準備ができたら、CallBack2メソッドが呼び出されます。
最後に、コールバックが呼び出され、AおよびjQueryモジュールの_compileメソッドが実行されます。
最初に、A.JSモジュールをコンパイルし、モジュールaの関数を実行します。 Aには(b.js)が必要なため、モジュールbの関数が実行されます。
モジュールAの機能は実行を開始します
モジュールBの機能が実行され始めます
モジュールCの機能は実行を開始します
モジュールCの関数実行が完了しました
モジュールBの関数実行が完了しました
モジュールAの関数実行が完了しました
最後に、jQueryの関数を実行します。
コンパイル後、callback1を実行すると、aおよびjqueryオブジェクトを使用できます。
PS:SEAJSバージョンが更新されており、現在_compileメソッドはありません。 (誰もが自分でそれを見に行きます、私も見たいです)
SEAJSモジュールcompilation_compileプロセスについて話しましょう。
まず、A.JSの編集
コードコピーは次のとおりです。
module.prototype._compile = function(){
126 varモジュール=これ
127 //モジュールがコンパイルされている場合は、モジュールを直接返す
128 if(module.status === status.compiled){
129 Return Module.Exports
130}
133 //1。モジュールファイルは404です。
134 //2。モジュールファイルは、有効なモジュール形式で記述されていません。
135 //3。他のエラーケース。
136 //ここに対処するためのいくつかの例外があり、その後直接nullを返します
137 if(module.status <status.saved &&!hasmodifiers(module)){
138返品null
139}
140 //モジュールステータスをコンパイルして変更します。つまり、モジュールがコンパイルされていることを意味します
141 module.status = status.compiling
142
143 //モジュールの内部使用は、他のモジュール(サブモジュールと呼ばれる)によって提供されたインターフェイスを取得し、同期的に動作するために使用される方法です
144関数は(id){
145 //パスIDに従ってモジュールのパス
146 var uri = Resolve(id、module.uri)
147 //モジュールキャッシュからモジュールを取得します(メインモジュールとしてのサブモジュールの依存関係はダウンロードされていることに注意してください)
148 var child = cachedmodules [uri]
149
150 // URIが無効な場合はnullを返します。
151 //子供が空の場合、パラメーターが誤って埋められていることを意味するだけで、直接nullを返します
152 if(!child){
153返品null
154}
155
156 //循環通話を避けます。
157 //サブモジュールのステータスがstatus.compilingである場合、child.exportsを直接返して、円形の依存関係によりモジュールの繰り返しの編集を避けます。
158 if(child.status === status.compiling){
159 return child.exports
160}
161 //初期化中に現在のモジュールを呼び出すモジュールを指します。このプロパティに基づいて、モジュールが初期化されたときにコールスタックを取得できます。
162 child.parent =モジュール
163 //コンパイルされた子供のモジュールを返します
164 return child._compile()
165}
166 //内部で使用されてモジュールを非同期ロードし、読み込みが完了した後に指定されたコールバックを実行します。
167 require.async = function(ids、callback){
168 module._use(ids、callback)
169}
170 //モジュールシステム内のパス解像度メカニズムを使用して、モジュールパスを解析して返します。この関数はモジュールをロードせず、解析された絶対パスのみを返します。
171 require.resolve = function(id){
172 Return Resolve(id、module.uri)
173}
174 //このプロパティを通じて、モジュールシステムによってロードされたすべてのモジュールを表示できます。
175 //場合によっては、モジュールをリロードする必要がある場合は、モジュールのURIを取得し、delete require.cache [uri]によって情報を削除できます。これは、次に使用するときに再取得されます。
176 require.cache = cachedmodules
177
178 //要求は、他のモジュールによって提供されるインターフェイスを取得する方法です。
179 module.require = require
180 //エクスポートは、モジュールインターフェイスを外側に提供するオブジェクトです。
181 module.exports = {}
182 var Factory = module.Factory
183
184 //工場が関数である場合、モジュールのコンストラクターを表します。この方法を実行することにより、モジュールから外部に提供されるインターフェイスを取得できます。
185 if(util.iffunction(Factory)){
186 CompileStack.Push(モジュール)
187 RunInModuleContext(工場、モジュール)
188 compilestack.pop()
189}
190 //工場がオブジェクト、文字列などの非機能タイプである場合、モジュールを表すインターフェイスはオブジェクト、文字列、その他の値です。
191 //例:define({"foo": "bar"});
192 //例:define( '私はテンプレートです。私の名前は{{name}}。');
193 else if(factory!== undefined){
194 module.exports = Factory
195}
196
197 //コンパイルされるモジュールステータスを変更します。つまり、モジュールがコンパイルされています
198 module.status = status.compiled
199 // seajs.modify()を介してモジュールインターフェイスの変更を実行します
200 execModifiers(モジュール)
201 return module.exports
202}
コードコピーは次のとおりです。
if(util.isfunction(Factory)){
186 CompileStack.Push(モジュール)
187 RunInModuleContext(工場、モジュール)
188 compilestack.pop()
189}
Module.Exportの初期化は次のとおりです。 runinmodulecontextメソッド:
コードコピーは次のとおりです。
//モジュールのコンテキストに従ってモジュールコードを実行する
489関数runinmodulecontext(fn、module){
490 //モジュールとモジュール自体に関連する2つのパラメーターで渡す
491 //エクスポートは、インターフェイスの露出に使用されます
492 //依存するモジュールを取得するために要求が使用されます(同期)(コンパイル)
493 var ret = fn(module.require、module.exports、module)
494 //次のようなリターン値の露出のインターフェイス形式をサポートしています。
495 // return {
496 // fn1:xx
497 //、fn2:xx
498 // ...
499 //}
500 if(ret!== undefined){
501 module.exports = ret
502}
503}
a.jsで関数メソッドを実行すると、var b = require( "b.js")が呼び出されます。
要件メソッドは、bのコンパイルメソッドの返品値を返し、bモジュールにvar c = require( 'c.js')があります。
この時点で、Cのコンパイル方法が呼び出され、Cの関数が呼び出されます。 Cでは、オブジェクトが公開される場合、または戻りオブジェクトCが返される場合、モジュールCのエクスポートはエクスポート= cになります。または直接module.export = c;要するに、モジュールc.Export = Cは最終的に返されます。したがって、var c =モジュールC.Export = c。モジュールBでは、変数Cを使用して、モジュールcのCオブジェクトのメソッドとプロパティを呼び出すことができます。
類推により、モジュールAは最終的にモジュールbのBオブジェクトのプロパティとメソッドを呼び出すことができます。
どのモジュールに関係なく、モジュールを使用している限り、Export = XXモジュールでは、他のモジュールがXXモジュールのさまざまなメソッドを呼び出すために必要な( "xxモジュール")を使用できます。
最終的なモジュール状態は、module.status = status.compiledになります。
コードコピーは次のとおりです。
module.prototype._use = function(ids、callback){
var uris = Resolve(ids、this.uri); //解像度['./a'、'Jquery']
this._load(uris、function(){//解析されたaおよびjqueryモジュール[url1、url2]のアドレスを呼び出し、_loadメソッドを呼び出します。
//util.map:すべてのデータメンバーに指定された関数を一度に実行し、元の配列メンバーのコールバック実行の結果である新しい配列を返します
var args = util.map(uris、function(uri){
uriを返しますか? cachedmodules [uri] ._ compile():null; // urlが存在する場合、_compileメソッドを呼び出します。
})
if(callback){callback.apply(null、args)}
})
}
この時点でargss = [モジュールA.Export、モジュールjQuery.Export];
コードコピーは次のとおりです。
seajs.use(['./ a'、 'jquery']、function(a、$){
var num = aa;
$( '#j_a')。text(num);
})
この時点で、関数のaと$はモジュールA.ExportおよびModule JQuery.Exportです。
私は現在、jqueryソースコードとjqueryフレームワークのデザインを勉強しているので、いくつかの経験を共有しています。
jQueryソースコード、私はオンラインで多くの分析を読みましたが、私はそれを見ている間、もうそれを読むことができません。それはあまり意味がないので、Miaowei ClassroomのjQueryソースコード分析をお勧めします。
Situ ZhengmeiのJavaScriptフレームワークの設計は困難ですが、慎重に読んだ後、シニアのフロントエンドエンジニアになります。
Yu Bo's Sea.jsを学び、使用することをお勧めします。結局のところ、それは中国人自身によって作られています。当社の新しいプロジェクトまたは再建は、SEAJを使用して行われます。
次は、モジュラーハンドバーとMVCバックボーンまたはMVVM Angularのソースコード集約型読み取り値です。ここでは、誰かが私に、どの本、ウェブサイト、ビデオを迅速に学ぶかについて提案をしてくれることを願っています。