Bevor die CommonJs-Spezifikation vorgeschlagen wurde, verfügte Javascript über kein Modulsystem, was bedeutete, dass es für uns schwierig war, umfangreiche Anwendungen zu entwickeln, da die Organisation des Codes schwieriger sein würde.
Erstens gilt CommonJS nicht nur für Node. Es handelt sich um eine Modulspezifikation, die definiert, wie Module referenziert und exportiert werden. Die CommonJS-Modulspezifikation ist hauptsächlich in drei Teile unterteilt: Modulreferenz, Moduldefinition und Modulidentifikation .
Modulreferenz
Modulreferenz bedeutet, dass wir andere Module über require
einführen können.
const { add } = require('./add'); const result = add(1,2);
Module definiert
eine Datei als Modul und das Modul stellt zwei Variablen bereit, nämlich module und exports. module ist das aktuelle Modul selbst, exports ist der zu exportierende Inhalt und exports ist ein Attribut des Moduls, d. h. exports ist module.exports. Der von anderen Modulen über require importierte Inhalt ist der Inhalt von module.exports.
// add.js exports.add = (a, b) => { gib a + b zurück; }
Modulidentifikation
Die Modulidentifikation ist der Inhalt in require. Beispiel: require('./add')
, dann ist die Modulidentifikation ./add
.
Der über CommonJS erstellte Mechanismus zum Importieren und Exportieren von Modulen ermöglicht es Benutzern, auf einfache Weise umfangreiche Anwendungen zu erstellen, ohne variable Verschmutzungen berücksichtigen zu müssen.
Implementierung des Knotenmoduls
Node implementiert die CommonJs-Spezifikation und fügt einige benötigte Funktionen hinzu. Node führt hauptsächlich die folgenden drei Dinge aus, um die CommonJs-Spezifikation zu implementieren:
Positionierung
, Kompilierung und Ausführung der
Pfadanalysedatei
.
Wenn require() ausgeführt wird, ist der von require empfangene Parameter die Modulkennung, und der Knoten führt die Pfadanalyse über die Modulkennung durch. Der Zweck der Pfadanalyse besteht darin, anhand der Modulkennung den Pfad zu ermitteln, in dem sich dieses Modul befindet. Zunächst werden Knotenmodule in zwei Kategorien unterteilt, nämlich Kernmodule und Dateimodule. Das Kernmodul ist das Modul, das mit dem Knoten geliefert wird, und das Dateimodul ist das vom Benutzer geschriebene Modul. Gleichzeitig werden Dateimodule in Dateimodule in Form relativer Pfade, Dateimodule in Form absoluter Pfade und Dateimodule in Form von Nicht-Pfaden (z. B. Express) unterteilt.
Wenn der Knoten ein Dateimodul findet, wird das Modul kompiliert, ausgeführt und zwischengespeichert. Das allgemeine Prinzip besteht darin, den vollständigen Pfad des Moduls als Schlüssel und den kompilierten Inhalt als Wert zu verwenden. Dies wird bei der Einführung des Moduls nicht benötigt Führen Sie dann zum zweiten Mal eine Pfadanalyse, Dateispeicherung, Kompilierung und Ausführung durch. Der kompilierte Inhalt kann direkt aus dem Cache gelesen werden.
//Cache-Moduldiagramm: const zwischengespeichertesModule = { '/Usr/file/src/add.js': 'Kompilierter Inhalt von add.js', 'http': 'Kompilierter Inhalt des http-Moduls, das mit Node geliefert wird', 'express': 'Kompilierter Inhalt des benutzerdefinierten Dateimoduls Express ohne Pfad' // ... }
Wenn Sie das von require importierte Modul finden möchten, besteht die Reihenfolge bei der Suche nach dem Modul darin, zunächst zu prüfen, ob sich das Modul bereits im Cache befindet. Wenn es sich nicht im Cache befindet, überprüfen Sie dann das Kernmodul und suchen Sie dann das Dateimodul. Unter diesen sind Dateimodule in Form von Pfaden leichter zu finden. Der vollständige Dateipfad kann anhand des relativen oder absoluten Pfads ermittelt werden. Es ist relativ mühsam, benutzerdefinierte Dateimodule in Nicht-Pfad-Form zu finden. Node sucht im Ordner „node_modules“ nach der Datei.
Wo ist das Verzeichnis node_modules? Die Datei, die wir gerade ausführen, ist /Usr/file/index.js
; * /Usr/file/index.js; */ const { add } = require('add'); const result = add(1, 2);
In diesem Modul haben wir ein Add-Modul eingeführt. Dieses Add ist weder ein Kernmodul noch ein Dateimodul in Form eines Pfads.
Das Modul verfügt über ein Pfadattribut. Der Pfad zum Suchen des hinzugefügten Moduls befindet sich im Pfadattribut. Wir können dieses Attribut eingeben, um einen Blick darauf zu werfen:
/** * /Usr/file/index.js; */ console.log(module.paths);
Wir können den Wert von Pfaden ausdrucken, indem wir node index.js im Dateiverzeichnis ausführen. Der Wert in paths ist ein Array wie folgt:
[ '/Usr/file/node_modules', '/Usr/node_modules', '/node_modules', ]
Das heißt, der Knoten durchsucht nacheinander das obige Verzeichnis, um festzustellen, ob es das Add-Modul enthält. Das Prinzip ähnelt der Prototypenkette. Beginnen Sie zunächst mit der Suche im Ordner „node_modules“ im Verzeichnis auf derselben Ebene wie die aktuell ausgeführte Datei. Wenn das Verzeichnis „node_modules“ nicht gefunden wird oder nicht vorhanden ist, fahren Sie mit der Suche auf der höheren Ebene fort.
DieDateipfadanalyse
und der Dateispeicherort können zusammen verwendet werden, oder ein Verzeichnis oder ein Paket kann durch eine Pfadanalyse gefunden werden.
Dateierweiterungsanalyse
const { add } = require('./add');
Im obigen Code hat der Dateibezeichner beispielsweise keine Erweiterung. Zu diesem Zeitpunkt sucht Node nach der Existenz von .js, .json , und .node nacheinander.
Die Verzeichnis- und Paketanalyse
entspricht dem obigen Code. Was über ./add
gefunden wird, ist möglicherweise keine Datei, sondern ein Verzeichnis oder ein Paket (beurteilen Sie, ob es sich um ein Verzeichnis oder ein Paket handelt, indem Sie beurteilen, ob ein Paket vorhanden ist). json-Datei im Add-Ordner). Zu diesem Zeitpunkt sind die Schritte zur Dateipositionierung wie folgt:
Wenn in package.json kein Hauptfeld vorhanden ist, wird index auch als Datei verwendet und anschließend eine Erweiterungsanalyse durchgeführt, um die Datei mit dem entsprechenden Suffix zu finden .
Modulkompilierung
Die Hauptmodule, denen wir in der Entwicklung begegnen, sind JSON-Module und JS-Module.
JSON-Modulkompilierung
Wenn wir ein JSON-Modul benötigen, hilft uns Node tatsächlich dabei, fs.readFilcSync zu verwenden, um die entsprechende JSON-Datei zu lesen, die JSON-Zeichenfolge abzurufen und dann JSON.parse zum Parsen aufzurufen, um das JSON-Objekt abzurufen und es dann zuzuweisen Das Modul exportiert es und gibt es dann an die Anforderung weiter.
js-Modulkompilierung
Wenn wir ein js-Modul benötigen, z. B.
// index.js const { add } = require('./add');
// add.js exports.add = (a, b) => { gib a + b zurück; }
Was ist zu diesem Zeitpunkt passiert? Warum können wir die Variablenmodule, Exporte und Require direkt im Modul verwenden? Dies liegt daran, dass Node beim Kompilieren des js-Moduls den Inhalt des Moduls zuerst und zuletzt umschließt.
Beispielsweise wird das Modul add.js beim tatsächlichen Kompilieren in eine ähnliche Struktur gepackt:
(function(require, exports, module) { exports.add = (a, b) => { gib a + b zurück; } return module.exports; })(require, module.exports, module)
Das heißt, die von uns geschriebene js-Datei wird in eine Funktion gepackt. Was wir schreiben, ist nur der Inhalt dieser Funktion, und der nachfolgende Verpackungsprozess von Node ist uns verborgen. Diese Funktion unterstützt die Übergabe einiger Parameter, einschließlich require, exports und module.
Nachdem die js-Datei kompiliert wurde, übergibt der Knoten die entsprechenden Parameter an diese Funktion, führt sie dann aus und gibt den module.exports-Wert an die erforderliche Funktion zurück.
Das Obige ist der grundlegende Prozess für Node zur Implementierung der CommonJs-Spezifikationen.