Ich habe vor einiger Zeit den Quellcode von require.js analysiert, und der Inhalt war etwas allgemein Etwas leer und unklar. Das Wesentliche an der Abhängigkeitsverarbeitung von requirejs ist der am häufigsten fehlgeschlagene Teil bei der Analyse des Quellcodes von require.js.
Obwohl ich die Implementierungsdetails nicht wirklich verstehe, habe ich ein allgemeines Verständnis für die Organisation des Quellcodes und die grundlegende Logikausführung.
Dieser Artikel bezieht sich auf den Quellcode im Internet und analysiert den einfachen Modullader, der durch seine Ideen implementiert wird, mit dem Ziel, das Wissen und Verständnis von require.js zu vertiefen.
Zunächst sind folgende Punkte klar:
Jedes Mal, wenn die Anforderungsfunktion aufgerufen wird, Es wird ein Kontext erstellt. Das Objekt
Modulobjekt stellt das Modulobjekt dar, und die Grundoperationen sind die Prototypmethoden des Objekts
Das Die beiden oben genannten Objekte dienen zur Implementierung dieses einfachen Moduls. Der Laderkern, der Verarbeitungsablauf während des Ladevorgangs ist in der folgenden Abbildung dargestellt:
Die Eigenschaften des Moduls Objekt sind:
mid: Gibt die Modul-ID
an src: Modulpfad
Name: Modulname
deps: Modulabhängigkeitsliste
Rückruf: Rückruffunktion
errback: Fehlerbehandlungsfunktion
Status: Modulstatus
Exporte: Modulausgabe entsprechend der Callback-Funktionsparametersequenz
Das Prototypobjekt des Moduls verfügt über die folgenden Methoden:
init: Initialisierungsverarbeitung des Modulobjekts
fetch: Erstellen Sie einen Skriptknoten und hängen Sie ihn an den Elementknoten
an checkCycle: behandelt zyklische Abhängigkeiten und gibt die aktuelle zyklische Abhängigkeitsliste
zurück handleDeps: Handle-Abhängigkeitsliste
changeStatus: Ändern Sie den Status des Moduls und verarbeiten Sie hauptsächlich, ob das Modul erfolgreich geladen wurde
ausführen: Nachdem alle abhängigen Module erfolgreich geladen wurden, wie man die Parameterliste erhält
Tatsächlich wird die Abhängigkeitsliste verarbeitet ist define und require Bei der Verarbeitung lauten die Verarbeitungscodes von define function und require function wie folgt:
Sehen Sie sich zunächst die require-Funktion an, Beispiel:
require(['a', 'b'], function(a, b) { console.log(a, b); });
Wie aus dem Obigen ersichtlich ist, heißt die Anforderungsfunktion, die Abhängigkeitsliste ist ['a', 'b'] und die Rückruffunktion ist function(a, b) {console.log(a, b);}
Wie aus dem Anforderungscode ersichtlich ist, wird beim Aufrufen des Context-Konstruktors ein Context-Objekt erstellt. Schauen wir uns nun die Verarbeitung des Context-Konstruktors an: let Context = function(deps, callback, errback) {
this.cid = ++contextId; this.init(deps, callback, errback); } ; Context.prototype.init = function(deps, callback, errback) { this.deps = deps; this.callback = callback; this.errback = errback; contexts[this.cid] = this; } ;
Das Wichtigste im Obigen ist contexts[this.cid ] = this; Registrieren Sie das aktuelle Kontextobjekt in der globalen Kontextobjektsammlung.
Rufen Sie dann die Funktion handleDeps auf, die die Abhängigkeitsliste verarbeitet. Der spezifische Code lautet wie folgt: handleDeps: function() {
let depCount = this.deps ? this.deps.length : 0; // require.js中处理循环依赖的处理 let requireInDep = (this.deps || []).indexOf('require'); if (requireInDep !== -1) { depCount--; this.requireInDep = requireInDep; this.deps.splice(requireInDep, 1); } // 处理循环依赖情况 let cycleArray = this.checkCycle(); if (cycleArray) { depCount = depCount - cycleArray.length; } // depCount表示当前模块的依赖模块数,depCount为0表示模块中某一依赖加载完成 this.depCount = depCount; if (depCount === 0) { this.execute(); return; } // 遍历依赖列表,创建Module对象,并且将当前模块与其依赖的关系构建出来maps this.deps.forEach((depModuleName) => { if (!modules[depModuleName]) { let module = new Module(depModuleName); modules[module.name] = module; } if (!maps[depModuleName]) { maps[depModuleName] = []; } maps[depModuleName].push(this); } );
} Behandlung zirkulärer Abhängigkeiten
Die offizielle Methode in require.js besteht darin, zirkuläre Abhängigkeiten in diesem Implementierungscode zu behandeln, nämlich require und require erneut in der Rückruffunktion zu übergeben. Warum kann dies gelöst werden? Zirkuläre Abhängigkeiten? ?
Was diese Implementierung betrifft, wird require einmalig ein Kontextobjekt erstellen. Der Hauptcode lautet wie folgt: // Verarbeitung zirkulärer Abhängigkeiten in require.js let requireInDep = (this.deps || []).indexOf('require');
if (requireInDep !== -1) { depCount--; this.requireInDep = requireInDep; this.deps.splice(requireInDep, 1); } // 获取循环依赖 let cycleArray = this.checkCycle(); if (cycleArray) { depCount = depCount - cycleArray.length; } // execute函数中代码// 插入require到回调函数的参数列表中if (this.requireInDep !== -1 && this.requireInDep !== undefined) { arg.splice(this.requireInDep, 0, require); }
Fazit
Was ich auf dem Papier gelernt habe, ist endlich klar, und mir ist klar, dass diese Angelegenheit durch die Implementierung eines einfachen Modulladers, der Idee und der logischen Verarbeitung von require.js umgesetzt werden muss Modulladung wird klarer.
Obwohl require.js das asynchrone Laden von js-Dateien unterschiedlich handhabt, ist das Wesentliche dasselbe: require.js fügt dem Head-Tag einen Skriptknoten hinzu, und das Skript fügt das asynchrone Laden hinzu.
Das obige ist der detaillierte Inhalt vonSo implementieren Sie einen einfachen Modullader mit js. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!