コンテンツ
序文
ここで説明するモジュールのロードプロセスでは、定義の定義の形式についてのみ説明し、取得が必要です。
これには、configでのdata-mainおよび依存モジュールのロードプロセスは含まれません。
レビュー
requirejsの初期化プロセス:
1.さまざまなAPIと関数を初期化します
1)、req = require = requirejs、req.config、req.load、define等。
2.newContextのコア
1)、内部で使用されるさまざまなデータ構造を定義します
2)、コンテキストの中心的なデータ構造
3)、モジュールの基本操作単位
3.requireの構成を完了します
プログラムエントリー
前回と同じ番組エントリーで、またここに掲載されています。
<!--我在这里并不使用data-main方式,具体原因参考官网-->
<script src="require.js" type="text/javascript"></script>
<script>
require.config({
baseUrl:"js",
paths:{
app:"./app",
}
});
require(["app"],function(){
console.log("This is index.html,require app success!");
});
</script>
require.configの実行プロセス
初期化プロセスを直接スキップして、require.configに移動します。
req.config = function (config) {
return req(config);
};
require.configは実際にはreq(config)を呼び出すため、reqの内部に直接移動します。
最後に、context.configure(config)を使用してデフォルトの構成アイテムを変更します。
注:deps関連の構成をconfigに追加する場合、require.configのプロセスには、依存関係のdepsへのロードが含まれます。ここでは、deps構成を追加しなかったため、プロセスは非常に単純です。
モジュールをロードするためにこのAPIを要求するプロセス
require.configを実行した後、requireがアプリモジュールをロードする部分まで実行を続けます。
require(["app"],function(){
console.log("This is index.html,require app success!");
});
requireを入力した後、context.requireに移動します(前の記事で述べたように、この関数はモジュールロードのコアエントリです)。
ファローアップ
最初にtakeDefinesについて説明しましょう。これはロードされる最初のモジュールであるため、これまでのところ、globalDefQueueには要素がないため、実際には実質的なことは何も行われません。
次に、context.nextTickを介してモジュールの読み込みタスクが作成されます。この読み込みタスクは、次のイベントループで実行され、depsに含まれるモジュール(アプリ)を読み込みます。
注意点:
requireを呼び出す前に、初期化プロセスでreq()が2回呼び出されます。これら2つの呼び出しのパラメーターは空のオブジェクトであるため、context.configureは実行されません。したがって、最後にcontext.requireのみが呼び出され、最後に2つの空のモジュールロードタスクを生成します。
その後、require.configを実行し、実際にreq(config)を実行します。今回はconfigが空のオブジェクトではないため、context.configureが1回呼び出されます。 )構成アイテム)、context.requireは呼び出されません。最後に、context.requireがreqの最後に1回呼び出されるため、モジュールのロードタスクが空になります。
したがって、requireを呼び出す前に、合計3つの空のモジュールタスクが生成されるため、4番目のモジュール読み込みタスクのみがアプリに対応するモジュールタスクになります。
この空の呼び出しは私の前の記事で不平を言いました、そして理由もなくさらに3つの役に立たないタスクがありました。
この時点で、requireの実行が終了し、次のイベントループに入ると、モジュールのロードタスクが実行されます。
ここでは、モジュール読み込みタスクの内部実行に入りました。
globalDefQueueはまだ空のキューであるため、takeDefinesは効果がありません。
次に、getModule(makeModuleMap(null、relMap))を実行して入力します。これは非常に重要なリンクであり、ここで多くの作業が行われました。
まず、makeModule関数を見てみましょう。
function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
var url, pluginModule, suffix, nameParts,
prefix = null,
parentName = parentModuleMap ? parentModuleMap.name : null,
originalName = name,
isDefine = true,
normalizedName = '';
//If no name, then it means it is a require call, generate an
//internal name.
if (!name) {
isDefine = false;
name = '_@r' + (requireCounter += 1);
}
nameParts = splitPrefix(name);
prefix = nameParts[0];
name = nameParts[1];
if (prefix) {
prefix = normalize(prefix, parentName, applyMap);
pluginModule = getOwn(defined, prefix);
}
//Account for relative paths if there is a base name.
if (name) {
if (prefix) {
if (isNormalized) {
normalizedName = name;
} else if (pluginModule && pluginModule.normalize) {
//Plugin is loaded, use its normalize method.
normalizedName = pluginModule.normalize(name, function (name) {
return normalize(name, parentName, applyMap);
});
} else {
// If nested plugin references, then do not try to
// normalize, as it will not normalize correctly. This
// places a restriction on resourceIds, and the longer
// term solution is not to normalize until plugins are
// loaded and all normalizations to allow for async
// loading of a loader plugin. But for now, fixes the
// common uses. Details in #1131
normalizedName = name.indexOf('!') === -1 ?
normalize(name, parentName, applyMap) :
name;
}
} else {
//A regular module.
normalizedName = normalize(name, parentName, applyMap);
//Normalized name may be a plugin ID due to map config
//application in normalize. The map config values must
//already be normalized, so do not need to redo that part.
nameParts = splitPrefix(normalizedName);
prefix = nameParts[0];
normalizedName = nameParts[1];
isNormalized = true;
url = context.nameToUrl(normalizedName);
}
}
//If the id is a plugin id that cannot be determined if it needs
//normalization, stamp it with a unique ID so two matching relative
//ids that may conflict can be separate.
suffix = prefix && !pluginModule && !isNormalized ?
'_unnormalized' + (unnormalizedCounter += 1) :
'';
return {
prefix: prefix,
name: normalizedName,
parentMap: parentModuleMap,
unnormalized: !!suffix,
url: url,
originalName: originalName,
isDefine: isDefine,
id: (prefix ?
prefix + '!' + normalizedName :
normalizedName) + suffix
};
}
この関数は、実際には最後にモジュール関連のパラメーター情報を生成します。
アプリの最後のモジュール読み込みタスクによって生成されたmoduleMap情報は次のとおりです。
次にgetModuleが呼び出され、パラメーター情報は上記で生成されたmoduleMapです。
ここで、_ @ r5はモジュール読み込みエントリであり、requirejsはすべてのモジュールエントリのモジュールオブジェクトを作成します。
ヒント:
レジストリには、登録されたモジュールIDが格納されます。登録されたモジュールの場合、モジュールオブジェクトは自然に再生成されます。
id:これはrequirejs内のモジュールオブジェクトの一意のIDです。
module:各モジュールの抽象データ構造。
function getModule(depMap) {
var id = depMap.id,
mod = getOwn(registry, id);
if (!mod) {
mod = registry[id] = new context.Module(depMap);
}
return mod;
}
getModuleは、最初にモジュールがロードおよび登録されているかどうかを判別します。登録されている場合は、対応するModuleオブジェクトを直接返します。登録されていない場合は、新しいModuleオブジェクトを生成し、レジストリに登録します。
次に、initを呼び出して、モジュールのロードを開始します。
注意点:
ここで生成されるモジュールオブジェクトは、現在requireを呼び出すモジュールに対応しています。ここではindex.htmlで呼び出すため、このモジュールには名前がありません。requirejsは自動的に名前とIDを生成します。名前またはIDは_@r5です。
すべての初期モジュールロードエントリには名前がなく、requirejsはそれをモジュールとして扱い、そのモジュールオブジェクトを作成します。この初期モジュールオブジェクト名はrequirejsによって生成されます。
depsは、_ @ r5の依存モジュールのリストであり、モジュールオブジェクトは、後でdeps内のモジュールごとに生成されます。
更に:
enabled:trueは非常に重要であり、このモジュールをロードできることを示します。
ここで、モジュールオブジェクトは、以下に示すように、依存するモジュールのリスト[app]に関連付けられています。
requirejsのモジュールロードでは、一度に複数の依存モジュールをロードできるため、このdepsは配列であり、この関連付けのステップでは、今回ロードする必要のある複数の依存モジュールの配列を、以前に作成したモジュールオブジェクトに関連付けるだけです。
次に、このモジュールオブジェクトを使用して、deps配列内の各モジュールを徐々に操作します。
後で、requirejsはこのdeps配列をトラバースし、モジュールごとにモジュールオブジェクトを作成してから、個別にロードを開始します。
つまり、requirejsは、index.htmlでrequireを呼び出すコードをモジュールと見なします。モジュール名がないため、requirejsは自動的に生成します。
次に、initの最後に、this.enable関数が呼び出され、フォローアップしてこの関数を確認します。
enable関数は、このモジュールのすべての依存モジュールのモジュールオブジェクトを内部的に作成し、それらを個別にロードします。
矢印はdepsを横切り、deps内の各モジュールのモジュールオブジェクトを作成し、それをロードします。
矢印でそれぞれのコールバック関数をフォローアップします。
ここで、モジュールマップオブジェクトがアプリモジュール用に作成されます。
次に、on関数を介して、getModule関数がon内で呼び出され、アプリに対応するモジュールオブジェクトが作成され、レジストリに登録されます。
次に、このコールバック関数が最後まで実行され、context.enableが呼び出され、context.enableでは、最終的にmodule.enableが呼び出されます。
このとき、これはアプリに対応するモジュールを指します。つまり、アプリはアプリに対応するモジュールオブジェクトを介して読み込まれます。
この時点ではアプリが読み込まれていないため、アプリの詳細はまだ不明です。したがって、this.checkはここで最後に直接呼び出されます。
this.checkをフォローアップして、何が起こっているかを確認します。
上の画像でわかるように、this.fetchは最終的に呼び出されます。
this.loadはthis.fetchで再度呼び出されます。
this.loadでcontext.loadを呼び出します。
そして、context.loadは最終的にreq.loadを呼び出します。req.loadは前の記事で解析されました。この関数は、スクリプトノードを作成し、実際にスクリプトをロードするために使用されます。
実行後、index.htmlにもう1行あります。
この時点で、アプリモジュールがロードされます。
簡単な要約:
1.requireを介してモジュールのロードを入力します
2. localRequireと入力して、モジュールの読み込みタスクを作成します
3.モジュールロードタスクを実行します
1)index.htmlにrequire code部分のモジュールオブジェクトを作成します。モジュールの名前はrequirejsによって生成され、ここでは_@r5によって参照されます。
2)require(app here)にロードされたモジュールを、前の手順で(_ @ r5)オブジェクトのdepsとして取得し、(_ @ r5).initを呼び出して初期化プロセスを開始します。
3)(_ @ r5).initの後で、(_ @ r5).enableを呼び出して、依存関係をdepsでトラバースし、依存関係をdepsにロードします。
4. depsでの依存関係の読み込みプロセス(ここでは、依存関係にアプリしかないため、アプリのみが読み込まれた後に終了します)。
1)enableで実行し、各関数に到達し、この関数を介してdepsをトラバースし、各依存関係に対応する関数を呼び出します。depsにはアプリが1つしかないため、最後にアプリは1つだけになります。対応する関数。パラメータが呼び出されます。
2)対応する関数を入力して実行します。最初に、アプリのmoduleMapオブジェクトが作成されます。このオブジェクトには、name、id、urlの3つの重要なプロパティがあります。ここで、idはrequirejsが実行するモジュールの一意の識別子です。内部で使用、urlはスクリプトタグを最後に作成するために使用されるsrcソースであり、nameはモジュール名です。
3)次に、on関数を実行します(このon関数はコンテキスト内のものであり、モジュール内のものではありません。明確に区別する必要があります)。on関数内で、getModule呼び出しを介してアプリに対応するモジュールオブジェクトを返します。 、次にアプリを使用してこのモジュールオブジェクトを参照します。
4)次に、context.enableを呼び出し、次に(app).enableを呼び出します。
module.enableはモジュールロードモジュールのコア関数であり、モジュールのロードはこの関数で実装されていることがわかります。
5)最後に、(app).checkを呼び出し、次に(app).fetchを呼び出し、次に(app).loadを呼び出し、最後にcontext.loadを呼び出し、context.loadでreq.loadを呼び出し、次にscriptタグを呼び出します。ここで作成し、アプリをダウンロードします。