Seit seiner Gründung hat niemand JavaScript als Programmiersprache angesehen. Im Web 1.0 -Ära wurde diese Skriptsprache hauptsächlich für die Spezialeffekte der Form von Formularüberprüfung und Webseite verwendet. Erst in der Web 2.0-Ära verwendete Front-End-Ingenieure es, um die Benutzererfahrung auf der Webseite erheblich zu verbessern. Wenn JS immer beliebter wird, wird es in etwa Änderungen in der Werkzeugbibliothek, der Komponentenbibliothek, in Front-End-Framework und Front-End-Anwendungen unterzogen. JavaScript fehlt von Natur aus ein Merkmal: Module, und die Entstehung der CommonJS -Spezifikation macht diesen Mangel aus. In diesem Artikel wird der Mechanismus der CommonJS -Spezifikation und des Knotenmoduls eingeführt.
In anderen hochrangigen Sprachen verfügt Java über Klassendateien, Python hat einen Importmechanismus und PHP hat und benötigt. Die Art und Weise, wie JS Code über das <Script> -Tag einführt, scheint chaotisch zu sein. In der Vergangenheit mussten die Menschen Namespaces und andere Methoden verwenden, um den Code künstlich einzuschränken. Erst als die CommonJS-Spezifikation hervorgeht, konnte Front-End- und Back-End-JavaScript eine große Einheit erreichen. Die Knotenleiden leihen die Modulspezifikation von CommonJS, um ein sehr einfach zu bedienendes Modulsystem zu implementieren.
1. Spezifikation für CommonJS -Modul
Die Spezifikation des CommonJS -Moduls ist in 3 Teile unterteilt:
1). Modulreferenz: Führen Sie die API eines Moduls in den aktuellen Kontext durch die Methode Request () ein und geben Sie in eine Modul -Kennung wie var Math = Request ('Math').
2) .moduldefinition: Exportieren Sie die Methoden oder Variablen des aktuellen Moduls durch das Exportobjekt. Es gibt auch ein Modulobjekt im Modul, und Exporte sind tatsächlich das Attribut des Moduls. Im Knoten ist eine Datei ein Modul, und die "globalen Variablen" im Modul sind für die Außenwelt unsichtbar. Nur die auf Exporten montierten Attribute sind öffentlich, wie z. B. exports.add = function () {}; exports.pi = 3.1415926;
3) .modul id: Es ist tatsächlich der Parameter, den er verlangt hat (). Zum Beispiel muss die oben erwähnte "Mathematik" eine Zeichenfolge sein, die der Kamel -Nomenklatur oder einem relativen oder absoluten Pfad entspricht, beginnend mit "". ".." Es kann kein Dateinamen -Suffix haben ".js"
2. Implementierungsprozess des Knotenmoduls
Im Knoten sind Module in zwei Kategorien unterteilt: Einer ist das Kernmodul, das vom Knoten selbst bereitgestellt wird, und das andere ist das vom Benutzer selbst geschriebene Dateimodul. Einige der Kernmodule werden während der Kompilierung des Knotenquellcodes in Binärdateien zusammengestellt. Wenn der Knoten startet, wird das Kernmodul direkt in den Speicher geladen, sodass die Ladegeschwindigkeit die schnellste ist. Das Dateimodul wird zur Laufzeit dynamisch geladen und erfordert drei Schritte: Pfadanalyse, Dateispeicherort sowie Kompilierung und Ausführung. Beachten Sie, dass Knoten -Caches Module einführte, um den Overhead während der sekundären Einführung zu verringern, und die am meisten bevorzugte Strategie für die sekundäre Belastung desselben Moduls anwendet.
2.1 Pfadanalyse
Die Pfadanalyse analysiert hauptsächlich die oben genannten Modulerkennung, die hauptsächlich in die folgenden Kategorien unterteilt sind:
1) Kernmodule wie HTTP, FS, Pfad usw.
2) Relatives Pfaddateimodul beginnend mit. oder .
3) Absolutes Path -Dateimodul beginnend mit /
4) Benutzerdefinierte Dateimodul, die möglicherweise in Form einer Datei oder eines Pakets vorliegt. Der Knoten versucht, die Zieldatei nacheinander gemäß dem Modulpfad-Array-Modul zu finden.
2.2 Dateispeicherort
Basierend auf der Pfadanalyse müssen die folgenden Details beachtet werden:
1) Dateierweiterungsanalyse: Da die CommonJS -Spezifikation die Ausgabe von Modulkennungen ermöglicht, versucht der Knoten in der Reihenfolge von .js, .json und .node
2) Verzeichnisanalyse und -paket: Wenn nach der obigen Dateierweiterungsanalyse keine entsprechende Datei gefunden wird, ein Verzeichnis jedoch erhalten wird, behandelt der Knoten das Verzeichnis als Paket.
2.3 Zusammenstellung und Ausführung
Nachdem der Knoten die spezifische Datei suchen, erstellt der Node ein neues Modulobjekt, lädt und kompiliert entsprechend dem Pfad. Für unterschiedliche Erweiterungen ist die Lademethode unterschiedlich:
1) .js Datei: Lesen Sie die Datei synchron über das FS -Modul und kompilieren Sie sie und führen Sie sie aus
2) .node -Datei: Dies ist eine in C/C ++ geschriebene Erweiterungsdatei, die über die Methode dlopen () geladen wird
3) .JSON -Datei: Lesen Sie die Datei synchron über das FS -Modul und verwenden Sie JSON.Parse (), um das Ergebnis zu analysieren und zurückzugeben
4) Andere Erweiterungsdateien: Sie werden als .js -Dateien geladen
Wir wissen, dass jede Moduldatei drei Variablen hat: Erfordernis, Exporte und Modul standardmäßig. Selbst im Knoten -API -Dokument wissen wir, dass jedes Modul auch zwei Variablen hat: Dateiname und DirName. Woher kommen sie? Wie erreicht das Knotenmodul, dass die deklarierten "globalen Variablen" andere Module nicht tatsächlich verschmutzen? Tatsächlich wickelt der Knoten den Dateiinhalt am Anfang und am Ende während des Zusammenstellens des JS -Moduls ein. Hier ist ein Beispiel für eine JS -Datei, die von Kopf und Schwanz verpackt wird:
Die Codekopie lautet wie folgt:
(Funktion (exportiert, erfordern, modul, __FileName, __DIRNAME) {{
/* Die Mitte ist der tatsächliche Inhalt der JS -Datei*/
var math = fordert ('math');
exports.area = function (radius) {
return math.pi * radius * radius;
};
/* Der tatsächliche Inhalt der JS -Datei endet*/
});
Auf diese Weise besteht jede Moduldatei mit Scoped Isolation, und Variablen wie Erfordernisse werden ebenfalls Exporte, Module usw. in den Modulkontext injiziert. Dies ist die Implementierung der CommonJS -Modulspezifikation des Knotens. Der Kompilierungsprozess des C/C ++ - Moduls und des Knotenkernmoduls ist relativ kompliziert, daher werde ich es nicht wieder wiederholen.
3. Modul -Anrufstack
Es ist notwendig, die aufrufenden Beziehungen verschiedener Module im Knoten zu klären, wie in der folgenden Abbildung gezeigt:
Das eingebaute Modul von C/C ++ ist das Modul mit niedrigster Ebene und gehört zum Kernmodul. Es bietet hauptsächlich APIs, um JavaScript-Kernmodule und Javascript-Dateimodule von Drittanbietern aufzurufen. Tatsächlich gibt es fast keinen Kontakt mit solchen Modulen. Es gibt zwei Hauptaufgaben von JavaScript-Kernmodulen: Eine soll als Kapselungsschicht und die Überbrückungsschicht des integrierten Moduls C/C ++ für Dateimodulaufrufe dienen, und das andere ist ein reines Funktionsmodul, das sich nicht mit der zugrunde liegenden Ebene befassen muss. Dateimodule werden normalerweise von Dritten geschrieben, einschließlich gewöhnlicher JavaScript -Module und C/C ++ - Erweiterungsmodule.
4. Paket und NPM
4.1 Packungsstruktur
Das Paket ist im Wesentlichen eine Archivdatei (normalerweise .zip oder .tar.gz), die nach der Installation dekomprimiert und in ein Verzeichnis wiederhergestellt wird. CommonJS -Paketspezifikation besteht aus zwei Teilen: Paketstruktur und Paketbeschreibungsdatei. Eine Paketstruktur, die der CommonJS -Spezifikation vollständig entspricht, sollte die folgenden Dateien enthalten:
1) .package.json: Paketbeschreibung Datei
2) .bin: Das Verzeichnis, in dem ausführbare Binärdateien gespeichert sind
3) .LIB: Das Verzeichnis, in dem JavaScript -Code gespeichert ist
4) .doc: Das Verzeichnis, in dem das Dokument gespeichert ist
5). Test: Das Verzeichnis, in dem Unit -Testfälle gespeichert werden
4.2 Paketbeschreibung Datei
Die Paketbeschreibungsdatei ist eine JSON -Datei - package.json, die sich im Stammverzeichnis des Pakets befindet, ist ein wichtiger Bestandteil des Pakets und wird verwendet, um die Übersichtsinformationen des Pakets zu beschreiben. Alle später erwähnten Verhaltensweisen von NPMs hängen eng mit den Feldern dieser Datei zusammen. Im Folgenden werden wir die Paket.json-Datei eines bekannten Web Framework Express-Projekts als Beispiel verwenden, um die Bedeutung einiger häufig verwendeter Felder zu veranschaulichen.
1) .Name: Paketname
2) .Deskription: Paketeinführung
3) .version: Die Versionsnummer muss "Semantic Version Control" entsprechen, siehe http://semver.org/
4). Abhängigkeiten: Verwenden Sie die Liste der Pakete, von denen das aktuelle Paket abhängen muss. Diese Eigenschaft ist sehr wichtig. NPM lädt das abhängige Paket automatisch über diese Eigenschaft
5). Repositories: Liste der Standorte für das Hosting -Quellcode
Die Verwendung anderer Felder kann an das npm -Paket verwiesen werden. JSON Beschreibung
4.3 Häufige Funktionen von NPM
NPM (Node Package Manager), allgemein bekannt als Node Package Manager. Die Hauptfunktion besteht darin, Knotenpakete zu verwalten, einschließlich: Installation, Deinstallation, Update, Ansicht, Suche, Veröffentlichung usw.
4.3.1 NPM -Paketinstallation
Es gibt zwei Arten der Installation von Knotenpaketen: lokale Installation und globale Installation. Der Unterschied zwischen den beiden ist wie folgt:
1). Lokale Installation NPM Install <Paketname>: Das Paket wird in das aktuelle Verzeichnis heruntergeladen und kann nur im aktuellen Verzeichnis verwendet werden.
2). Global Installation NPM Install -GT <Paketname>: Das Paket wird in ein bestimmtes Systemverzeichnis heruntergeladen und das installierte Paket kann in allen Verzeichnissen verwendet werden.
4.3.2 NPM -Paketverwaltung
Im Folgenden finden Sie eine Liste der häufig verwendeten Paketverwaltungsbefehle mit Grunn-Cli (Grunt-Befehlszeilen-Tool) als Beispiel:
1) .npm Installation: Installieren Sie alle von den Feldern der Abhängigkeiten und DevDependencies der Paket.json -Datei deklarierten Pakete
2) .npm installieren
3) .npm Installieren Sie Grunzen-Contrib-Copy-Save: Installieren Sie die Grunz-Contrib-Copy und speichern Sie die Abhängigkeit in der Paket.json-Datei
4) .npm Deinstallieren Grunzen-Cli: Deinstallationspaket deinstallieren
5) .NPM LISTE: Überprüfen Sie, welche Pakete installiert sind
6) .npm veröffentlichen <Ordner>: Paket veröffentlichen