requirejsのソースコード学習(02)-モジュールのロードプロセス

コンテンツ

序文

レビュー

プログラムエントリー

require.configの実行プロセス

モジュールをロードするためにこのAPIを要求するプロセス


序文

ここで説明するモジュールのロードプロセスでは、定義の定義の形式についてのみ説明し、取得が必要です。

これには、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タグを呼び出します。ここで作成し、アプリをダウンロードします。

おすすめ

転載: blog.csdn.net/lengye7/article/details/123754723
おすすめ