1. EinleitungWir wissen, dass Node.js basierend auf der CommonJS-Spezifikation modularisiert ist. Modularisierung ist ein unverzichtbares Werkzeug für komplexe Geschäftsszenarien. Vielleicht verwenden Sie es häufig, haben es aber nie systematisch verstanden. Deshalb werden wir heute über einige Dinge sprechen, die Sie über die Modularisierung von Node.js wissen müssen, und die Modularisierung von Node.js erkunden. 2. HaupttextIn Node.js sind zwei Module für die modulare Verwaltung integriert. Diese beiden Module sind auch zwei Schlüsselwörter, mit denen wir sehr vertraut sind: require und module. Integriert bedeutet, dass wir diese beiden Module im globalen Bereich verwenden können, ohne auf sie wie auf andere Module verweisen zu müssen.
Es ist nicht schwierig, in Node.js auf ein Modul zu verweisen. Es ist ganz einfach: const config = require('/Pfad/zur/Datei') Tatsächlich führt dieser einfache Code jedoch insgesamt fünf Schritte aus: Das Verständnis dieser fünf Schritte hilft uns, die Grundprinzipien der Modularität von Node.js zu verstehen und auch einige Fallstricke zu erkennen. Lassen Sie uns kurz zusammenfassen, was diese fünf Schritte bewirken:
Einige Schüler haben diese fünf Schritte möglicherweise verstanden und sind mit diesen Prinzipien vertraut, während andere möglicherweise mehr Zweifel haben. In jedem Fall werden im folgenden Inhalt die oben genannten Ausführungsschritte im Detail analysiert, in der Hoffnung, allen zu helfen, Fragen zu beantworten oder Wissen zu festigen und die Lücken zu schließen. Übrigens kannst du bei Bedarf wie ich ein Experimentalverzeichnis aufbauen und im Anschluss an die Demo Experimente durchführen. 2.1 Was ist ein Modul?Um Modularität zu verstehen, müssen Sie sich zunächst ansehen, was ein Modul ist. Wir wissen, dass Dateien in Node.js Module sind. Wir haben gerade erwähnt, dass Module .js-, .json- oder .node-Dateien sein können. Indem wir sie referenzieren, können wir Toolfunktionen, Variablen, Konfigurationen usw. abrufen, aber wie ist ihre spezifische Struktur? Um das Modul, also die Struktur des Modulobjekts, anzuzeigen, führen Sie einfach den folgenden Befehl in der Kommandozeile aus:
Es ist ersichtlich, dass ein Modul nur ein gewöhnliches Objekt ist, aber es gibt mehrere spezielle Attributwerte in der Struktur, die wir einzeln verstehen müssen. Einige Attribute wie ID, übergeordnetes Element, Dateiname und untergeordnetes Element müssen nicht einmal erklärt werden und können anhand ihrer wörtlichen Bedeutung verstanden werden. Die folgenden Inhalte helfen Ihnen, die Bedeutung und Funktion dieser Felder zu verstehen. 2.2 LösungNachdem wir ein allgemeines Verständnis davon haben, was Module sind, beginnen wir mit dem ersten Schritt, dem Auflösen, um das Prinzip der Modularisierung zu verstehen, d. h. wie Node.js das Zielmodul findet und den absoluten Pfad des Zielmoduls generiert. Warum haben wir also gerade jetzt das Modulobjekt ausgedruckt, damit jeder die Struktur des Moduls versteht? Denn es gibt zwei Feldwerte – ID, Pfade und Auflösungsschritte – die eng miteinander verknüpft sind. Schauen wir es uns gemeinsam an. Zuerst das ID-Attribut: Jedes Modul verfügt über ein ID-Attribut, das normalerweise den vollständigen Pfad des Moduls darstellt. Node.js kann diesen Wert verwenden, um das Modul zu identifizieren und zu lokalisieren. Aber hier gibt es kein spezielles Modul, wir geben lediglich die Modulstruktur in der Befehlszeile aus, daher handelt es sich um den Standardwert <repl> (repl steht für interaktiver Interpreter). Als nächstes folgt das Pfadattribut: Was ist die Funktion dieses Pfadattributs? Node.js ermöglicht es uns, Module auf verschiedene Arten zu referenzieren, z. B. über relative Pfade, absolute Pfade und voreingestellte Pfade (die in Kürze erläutert werden). Angenommen, wir müssen auf ein Modul namens „find-me“ verweisen. Wie hilft uns require, dieses Modul zu finden? erfordern('finde mich') Lassen Sie uns ausdrucken, was sich in den Pfaden befindet: ~/Lernknoten $ Knoten > Modulpfade [ '/Benutzer/samer/learn-node/repl/node_modules', '/Benutzer/samer/learn-node/node_modules', '/Benutzer/samer/node_modules', '/Benutzer/node_modules', '/Knotenmodule', '/Benutzer/samer/.node_modules', „/Benutzer/samer/.node_libraries“, '/usr/local/Cellar/node/7.7.1/lib/node' ] Ok, es handelt sich eigentlich um eine Reihe absoluter Systempfade. Diese Pfade stellen die möglichen Standorte aller Zielmodule dar und sind geordnet, was bedeutet, dass Node.js alle in den Pfaden aufgelisteten Pfade der Reihe nach durchsucht. Wenn das Modul gefunden wird, wird der absolute Pfad des Moduls zur späteren Verwendung ausgegeben. Jetzt wissen wir, dass Node.js in diesem Verzeichnisstapel nach Modulen sucht. Wir versuchen, require('find-me') auszuführen, um das Find-Me-Modul zu finden. Da wir das Find-Me-Modul in keinem Verzeichnis abgelegt haben, kann Node.js das Zielmodul nach Durchlaufen aller Verzeichnisse nicht finden und meldet daher den Fehler „Modul 'find-me' kann nicht gefunden werden“. Dieser Fehler wird möglicherweise häufig angezeigt:
Jetzt können Sie versuchen, das Find-Me-Modul, auf das Sie verweisen müssen, in einem der oben genannten Verzeichnisse abzulegen. Hier erstellen wir ein node_modules-Verzeichnis und eine find-me.js-Datei, damit Node.js es finden kann:
Nach dem manuellen Erstellen der Datei find-me.js hat Node.js das Zielmodul gefunden. Wenn das Find-Me-Modul im lokalen node_modules-Verzeichnis von Node.js gefunden wird, wird natürlich nicht weiter in nachfolgenden Verzeichnissen gesucht. Studenten mit Node.js-Entwicklungserfahrung werden feststellen, dass es beim Verweisen auf ein Modul nicht notwendig ist, eine genaue Datei anzugeben. Sie können das Zielmodul auch referenzieren, indem Sie auf das Verzeichnis verweisen, zum Beispiel:
Die Datei index.js im Find-Me-Verzeichnis wird automatisch importiert. Natürlich unterliegt dies Regelbeschränkungen. Der Grund, warum Node.js die Datei index.js im Find-Me-Verzeichnis finden kann, liegt darin, dass die Standardregel für den Modulimport darin besteht, nach der Datei index.js zu suchen, wenn der spezifische Dateiname fehlt. Wir können auch die Importregeln ändern (durch Modifizierung von package.json), zum Beispiel index -> main:
2.3, erfordern.lösenWenn Sie lediglich ein Modul in Ihr Projekt einführen möchten, ohne es sofort auszuführen, können Sie die Methode require.resolve verwenden, die der Methode require ähnelt, mit dem Unterschied, dass die Methode des eingeführten Moduls nicht ausgeführt wird:
Wie Sie sehen, druckt Node.js den vollständigen Pfad des Moduls, wenn das Modul gefunden wird. Wenn es nicht gefunden wird, wird ein Fehler gemeldet. Nachdem wir nun wissen, wie Node.js nach Modulen sucht, schauen wir uns an, wie Node.js Module lädt. 2.4. Eltern-Kind-Abhängigkeit zwischen ModulenWir drücken die Referenzbeziehung zwischen Modulen als Eltern-Kind-Abhängigkeitsbeziehung aus. Erstellen Sie einfach eine lib/util.js-Datei und fügen Sie eine console.log-Anweisung hinzu, um anzuzeigen, dass dies ein referenziertes Untermodul ist.
Geben Sie außerdem eine Zeile mit console.log-Anweisungen in index.js ein, um dies als übergeordnetes Modul zu identifizieren und auf die gerade erstellte lib/util.js als Untermodul zu verweisen.
Führen Sie index.js aus, um die Abhängigkeiten zwischen ihnen anzuzeigen:
Hier konzentrieren wir uns auf zwei Eigenschaften im Zusammenhang mit Abhängigkeiten: untergeordnete Elemente und übergeordnete Elemente. Im gedruckten Ergebnis enthält das Feld „Kinder“ das importierte Modul „util.js“, was darauf hinweist, dass es sich bei util.js um ein Untermodul handelt, von dem index.js abhängt. Wenn wir uns jedoch die übergeordnete Eigenschaft des Moduls util.js genauer ansehen, stellen wir fest, dass hier der Wert Circular erscheint. Der Grund dafür ist, dass beim Drucken der Modulinformationen eine zirkuläre Abhängigkeit generiert wird. Die übergeordneten Modulinformationen werden in den untergeordneten Modulinformationen gedruckt, und die untergeordneten Modulinformationen werden in den übergeordneten Modulinformationen gedruckt. Daher markiert Node.js es einfach als Circular. Warum müssen wir Eltern-Kind-Abhängigkeiten verstehen? Da dies mit der Art und Weise zusammenhängt, wie Node.js zirkuläre Abhängigkeiten behandelt, wird es später ausführlich beschrieben. Bevor wir uns mit dem Problem des Umgangs mit zirkulären Abhängigkeiten befassen, müssen wir zwei Schlüsselkonzepte verstehen: Exporte und Modulexporte. 2.5. Exporte, Modul.ExporteExporte: Exports ist ein spezielles Objekt, das ohne Deklaration direkt als globale Variable in Node.js verwendet werden kann. Es handelt sich tatsächlich um einen Verweis auf module.exports. Durch Ändern der Exporte kann der Zweck der Änderung von module.exports erreicht werden. Exports ist auch ein Eigenschaftswert in der gerade gedruckten Modulstruktur, aber die gerade gedruckten Werte sind alle leere Objekte, da wir in der Datei nicht damit gearbeitet haben. Jetzt können wir versuchen, ihm einfach einen Wert zuzuweisen: // Fügen Sie am Anfang von lib/util.js eine neue Zeile exports.id = 'lib/util' hinzu. // Fügen Sie am Anfang von index.js eine neue Zeile exports.id = 'index' hinzu. Führen Sie index.js aus:
Sie können sehen, dass die beiden gerade hinzugefügten ID-Attribute erfolgreich zum Exportobjekt hinzugefügt wurden. Wir können auch beliebige andere Attribute als die ID hinzufügen, genau wie beim Bedienen gewöhnlicher Objekte. Natürlich können wir Exporte auch in eine Funktion umwandeln, zum Beispiel: Exporte = Funktion() {} Modul.Export: Das Objekt module.exports ist eigentlich das, was wir schließlich durch require erhalten. Wenn wir ein Modul schreiben, erhalten andere, die auf das Modul verweisen, den Wert, den wir module.exports zuweisen. Beispielsweise in Kombination mit der vorherigen Operation auf lib/util: const util = erfordern('./lib/util'); console.log('UTIL:', util); // Ausgabeergebnis UTIL: { id: 'lib/util' } Da wir {id: 'lib/util'} gerade über das Exportobjekt an module.exports zugewiesen haben, ändert sich das Ergebnis von require entsprechend. Jetzt haben wir ein allgemeines Verständnis davon, was Exporte und module.exporte sind, aber es gibt ein kleines Detail zu beachten, nämlich, dass das Laden von Modulen in Node.js ein synchroner Prozess ist. Schauen wir uns noch einmal das geladene Attribut in der Modulstruktur an. Dieses Attribut gibt an, ob das Modul geladen wurde. Mit diesem Attribut lässt sich die Synchronisierung des Ladens von Node.js-Modulen leicht überprüfen. Wenn das Modul geladen wurde, sollte der geladene Wert wahr sein. Aber bisher ist jedes Mal, wenn wir ein Modul drucken, sein Status „false“. Das liegt eigentlich daran, dass das Laden von Modulen in Node.js synchron erfolgt. Wenn wir den Ladevorgang nicht abgeschlossen haben (der Ladevorgang umfasst das Markieren des Moduls, einschließlich des Markierens des geladenen Attributs), ist das gedruckte Ergebnis standardmäßig „geladen: falsch“. Wir verwenden setImmediate, um diese Informationen zu überprüfen: // In index.js setImmediate(() => { console.log('Das Modulobjekt index.js ist jetzt geladen!', Modul) }); Klicken und ziehen, um zu verschieben. Das Modulobjekt index.js ist jetzt geladen! Modul { Ausweis: '.', Exporte: [Funktion], übergeordnetes Element: null, Dateiname: '/Users/samer/learn-node/index.js', geladen: wahr, Kinder: [Modul { ID: '/Benutzer/samer/learn-node/lib/util.js', Exporte: [Objekt], übergeordnetes Element: [Rundschreiben], Dateiname: '/Users/samer/learn-node/lib/util.js', geladen: wahr, Kinder: [], Pfade: [Objekt] } ], Pfade: [ '/Benutzer/samer/learn-node/node_modules', '/Benutzer/samer/node_modules', '/Benutzer/node_modules', '/Knotenmodule' ] } Ok, da console.log nach Abschluss des Ladevorgangs abgelegt (markiert) wird, lautet der Ladestatus jetzt „geladen: true“. Dadurch wird vollständig überprüft, ob das Laden des Node.js-Moduls ein synchroner Prozess ist. Nachdem wir nun etwas über Exporte, module.exporte und die Synchronisierung des Modulladens wissen, wollen wir einen Blick darauf werfen, wie Node.js zirkuläre Abhängigkeiten von Modulen handhabt. 2.6. Zirkuläre ModulabhängigkeitIm obigen Inhalt haben wir gelernt, dass zwischen Modulen eine Eltern-Kind-Abhängigkeitsbeziehung besteht. Was macht Node.js, wenn zwischen Modulen eine zirkuläre Abhängigkeit auftritt? Angenommen, es gibt zwei Module, module1.js und module2.js, und sie verweisen wie folgt aufeinander: // lib/module1.js exporte.a = 1; require('./module2'); // Hier referenzieren exports.b = 2; exporte.c = 3; // lib/module2.js const Module1 = erfordern('./module1'); console.log('Modul1 ist hier teilweise geladen', Module1); // referenziere Modul1 und drucke es aus Versuchen Sie, module1.js auszuführen. Sie können die Ausgabe sehen:
Das Ergebnis gibt lediglich {a: 1} aus, während {b: 2, c: 3} fehlt. Bei genauerer Betrachtung von module1.js stellen wir fest, dass wir in der Mitte von module1.js, bevor exports.b = 2 und exports.c = 3 ausgeführt werden, einen Verweis auf module2.js hinzugefügt haben. Wenn wir diesen Ort den Ort nennen, an dem eine zirkuläre Abhängigkeit auftritt, dann ist das Ergebnis, das wir erhalten, die Eigenschaft, die exportiert wurde, bevor die zirkuläre Abhängigkeit auftritt. Dies basiert auch auf der Schlussfolgerung, dass das Laden von Modulen in Node.js ein synchroner Prozess ist, was wir oben überprüft haben. Node.js behandelt zirkuläre Abhängigkeiten auf einfache Weise. Während des Ladens des Moduls wird das Exportobjekt schrittweise aufgebaut und den Exporten werden Werte zugewiesen. Wenn wir ein Modul importieren, bevor es vollständig geladen ist, erhalten wir nur einige der Eigenschaften des exportierten Objekts. 2.7. .json und .nodeIn Node.js können wir „require“ nicht nur zum Verweisen auf JavaScript-Dateien verwenden, sondern auch zum Verweisen auf JSON- oder C++-Plug-ins (.json- und .node-Dateien). Wir müssen nicht einmal die entsprechende Dateierweiterung explizit deklarieren. Sie können die von require unterstützten Dateitypen auch in der Befehlszeile sehen:
Wenn wir require verwenden, um auf ein Modul zu verweisen, prüft Node.js zunächst, ob eine JS-Datei vorhanden ist. Wenn keine gefunden wird, wird eine Übereinstimmung mit der JSON-Datei gesucht. Wenn diese immer noch nicht gefunden wird, wird schließlich versucht, eine Übereinstimmung mit der Node-Datei zu finden. Um Verwirrungen und unklare Referenzabsichten zu vermeiden, können Sie im Allgemeinen der Regel folgen, beim Verweisen auf .json- oder .node-Dateien das Suffix explizit anzugeben und beim Verweisen auf .js-Dateien das Suffix wegzulassen (optional oder beides). .json-Datei: Es ist sehr üblich, auf JSON-Dateien zu verweisen. Beispielsweise lässt sich die statische Konfiguration in einigen Projekten einfacher verwalten, indem JSON-Dateien zum Speichern verwendet werden. Beispiel: { "Host": "lokaler Host", "Port": 8080 } Es ist ganz einfach, darauf zu verweisen oder es zu verwenden: const { Host, Port } = erforderlich('./config'); console.log(`Der Server wird unter http://${host}:${port} ausgeführt`) Die Ausgabe lautet wie folgt:
.node-Datei: Die .node-Datei wird aus einer C++-Datei konvertiert. Die offizielle Website bietet ein einfaches, in C++ implementiertes Hello-Plugin, das eine hello()-Methode verfügbar macht und den String „world“ ausgibt. Bei Bedarf können Sie dem Link folgen, um mehr zu erfahren und Experimente durchzuführen. Wir können node-gyp verwenden, um .cc-Dateien zu kompilieren und in .node-Dateien zu erstellen. Der Vorgang ist auch sehr einfach. Wir müssen nur eine binding.gyp-Datei konfigurieren. Ich werde hier nicht ins Detail gehen. Sie müssen nur wissen, dass Sie nach dem Generieren der .node-Datei normal auf die Datei verweisen und die darin enthaltenen Methoden verwenden können. Nachdem Sie beispielsweise hello() in die Datei addon.node konvertiert haben, können Sie darauf verweisen und es verwenden: const addon = erfordern('./addon'); Konsole.log(addon.hallo()); 2.8 UmhüllungTatsächlich haben wir im obigen Inhalt die ersten beiden Schritte zum Referenzieren eines Moduls in Node.js erläutert: Auflösen und Laden, die jeweils die Probleme des Modulpfads und des Ladens lösen. Schauen wir uns als Nächstes an, was Wrapping bewirkt. Wrapping bedeutet Verpacken, und das Objekt des Verpackens ist der gesamte Code, den wir im Modul geschrieben haben. Das heißt, wenn wir auf ein Modul verweisen, durchlaufen wir tatsächlich eine Schicht „transparenter“ Verpackung. Um diesen Verpackungsprozess zu verstehen, müssen Sie zunächst den Unterschied zwischen Exporten und Modulexporten verstehen. Exporte ist ein Verweis auf module.exports. Wir können Exporte in Modulen verwenden, um Eigenschaften zu exportieren, aber wir können es nicht direkt ersetzen. Zum Beispiel: exports.id = 42; // ok, jetzt verweist exports auf module.exports, was dem Ändern von module.exports entspricht. exports = { id: 42 }; // Nutzlos, verweist nur auf das Objekt { id: 42 }, keine tatsächlichen Änderungen an module.exports. module.exports = { id: 42 }; // OK, führe module.exports direkt aus. Sie fragen sich vielleicht, warum das Exportobjekt für jedes Modul ein globales Objekt zu sein scheint, aber erkennen kann, aus welchem Modul das exportierte Objekt stammt. Wie wird das gemacht? Bevor wir den Wrapping-Prozess verstehen, schauen wir uns ein kleines Beispiel an: // In a.js Var-Wert = "global" // In b.js console.log(Wert) // Ausgabe: global // In c.js console.log(Wert) // Ausgabe: global // In index.html ... <script src="a.js"></script> <script src="b.js"></script> <script src="c.js"></script> Wenn wir einen Wert im a.js-Skript definieren, ist dieser Wert global sichtbar und die nachfolgend eingeführten b.js und c.js können auf den Wert zugreifen. Dies ist jedoch in Node.js-Modulen nicht der Fall. In einem Modul definierte Variablen haben einen privaten Gültigkeitsbereich und können in anderen Modulen nicht direkt aufgerufen werden. Wie kommt dieser private Spielraum zustande? Die Antwort ist einfach. Vor dem Kompilieren des Moduls verpackt Node.js den Inhalt des Moduls in eine Funktion und implementiert den privaten Bereich über den Funktionsbereich. Mit require('module').wrapper können Sie die Wrapper-Eigenschaften ausdrucken:
Node.js führt keinen Code in der Datei direkt aus, sondern führt den Code über diese gewrappte Funktion aus, die jedem unserer Module einen privaten Bereich gibt und sich nicht gegenseitig beeinflusst. Diese Wrapper-Funktion hat fünf Parameter: Exports, Require, Module, __Filename, __Dirname. Wir können auf diese Parameter direkt über den Argumentparameter zugreifen und sie ausdrucken:
Werfen wir einen kurzen Blick auf diese Parameter. Der erste Parameter exports ist zunächst leer (nicht zugewiesen). Der zweite und dritte Parameter require und module sind Instanzen, die sich auf das von uns referenzierte Modul beziehen. Sie sind nicht global. Der vierte und fünfte Parameter __filename und __dirname stellen jeweils den Dateipfad und das Verzeichnis dar. Die gesamte gewrappte Funktion macht ungefähr dasselbe: unction (erfordern, Modul, __Dateiname, __Verzeichnisname) { lass exports = modul.exports; // Ihr Code ... Rückgabemodul.Exporte; } Kurz gesagt dient das Wrapping dazu, unseren Modulbereich zu privatisieren und Variablen oder Methoden mit module.exports als Rückgabewert zur Verwendung verfügbar zu machen. 2.9 ZwischenspeicherCaching ist leicht zu verstehen. Schauen wir es uns anhand eines Beispiels an:
Wie Sie sehen, wird das gleiche Modul zweimal referenziert, die Informationen werden jedoch nur einmal gedruckt. Dies liegt daran, dass der Cache für die zweite Referenz verwendet wird und das Modul nicht neu geladen werden muss. Drucken Sie require.cache, um die aktuellen Cache-Informationen anzuzeigen:
Sie können sehen, dass sich die gerade referenzierte Datei index.js im Cache befindet, sodass das Modul nicht neu geladen wird. Natürlich können wir den Cache-Inhalt auch löschen, indem wir require.cache löschen, um das Neuladen zu erreichen, aber ich werde es hier nicht demonstrieren. AbschlussIn diesem Artikel werden einige grundlegende Prinzipien und der gesunde Menschenverstand beschrieben, die Sie bei der Verwendung der Node.js-Modularisierung kennen müssen. Er soll allen zu einem klareren Verständnis der Node.js-Modularisierung verhelfen. In diesem Artikel werden jedoch keine tieferen Details erläutert, wie etwa die Verarbeitungslogik innerhalb der Wrapper-Funktion, das Problem des synchronen Ladens von CommonJS, der Unterschied zu ES-Modulen usw. Sie können weitere dieser nicht erwähnten Inhalte außerhalb dieses Artikels erkunden. Oben finden Sie eine ausführliche Erläuterung der NodeJS-Modularisierung. Weitere Informationen zur NodeJS-Modularisierung finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM! Das könnte Sie auch interessieren:
|
>>: Die Fallstricke bei der Bereitstellung von Angular-Projekten in Nginx
Inhaltsverzeichnis Konfiguration NFS-Server (nfs....
In diesem Artikelbeispiel wird der spezifische Co...
1. Reverse-Proxy-Beispiel 1 1. Erzielen Sie den E...
1. Problem Die Docker-Containerprotokolle führten...
Redis ist ein verteilter Cache-Dienst. Caching is...
Mysql ist eine beliebte und einfach zu bedienende...
rahmen: Stil = „Rahmenstil: durchgezogen; Rahmenbr...
Inhaltsverzeichnis Zwei Module zur Verwendung von...
Nginx ist ein leistungsstarker Website-Server und...
Inhaltsverzeichnis Installieren und Einführen von...
Um die Lebensdauer der Festplatte zum Speichern v...
Vorwort Die meisten Benutzer führen diesen Vorgan...
Das JD-Karussell wurde mit reinem HTML und CSS im...
Inhaltsverzeichnis So funktioniert es Betriebsabl...
Dieser Effekt tritt am häufigsten auf unserer Bro...