Fast jeder Node.js-Entwickler kann Ihnen sagen, was die Funktion require() macht, aber wie viele von uns wissen tatsächlich, wie sie funktioniert? Wir verwenden es täglich zum Laden von Bibliotheken und Modulen, aber sein Verhalten ist uns ein Rätsel.
Aus Neugier habe ich mich in den Kerncode des Knotens vertieft, um herauszufinden, was unter der Haube vor sich geht. Aber das ist keine einzelne Funktion. Ich habe module.js im Modulsystem des Knotens gefunden. Diese Datei enthält ein überraschend leistungsstarkes und relativ unbekanntes Kernmodul, das das Laden, Kompilieren und Zwischenspeichern jeder Datei steuert. „require()“ ist nur die Spitze des Eisbergs.
module.js
Die zweite Hauptaufgabe dieses Moduls besteht darin, den Modullademechanismus des Knotens zu verwalten. Die von uns verwendete unabhängige Operationsfunktion „require“ ist eigentlich ein abstraktes Konzept von module.require, das selbst nur eine einfache Kapselung der Funktion Module._load ist. Diese Lademethode übernimmt das eigentliche Laden jeder Datei und beginnt unsere Reise dorthin.
Module._load
Module._load ist für das Laden neuer Module und die Verwaltung des Modulcaches verantwortlich. Das Zwischenspeichern jedes geladenen Moduls reduziert die Anzahl redundanter Dateilesevorgänge und kann Ihre Anwendung erheblich beschleunigen. Darüber hinaus ermöglichen gemeinsam genutzte Modulinstanzen, dass Singleton-Funktionen von Modulen im Projektstatus verbleiben.
Wenn ein Modul nicht im Cache vorhanden ist, erstellt Module._load ein neues Basismodul dieser Datei. Anschließend weist es das Modul an, den Inhalt der neuen Dateien zu lesen, bevor es sie an module._compile sendet. [1]
Wenn Sie Schritt Nr. 6 oben bemerken, werden Sie sehen, dass module.exports an den Benutzer zurückgegeben wurde. Aus diesem Grund verwenden Sie beim Definieren einer zu verwendenden öffentlichen Schnittstelle exports und module.exports, da Module._load als nächstes den erforderlichen Inhalt zurückgibt. Ich bin überrascht, dass es hier nicht mehr Funktionen gibt, aber es wäre schön, wenn es welche gäbe.
module._compile
· Hier geschieht die wahre Magie. Zunächst wird für dieses Modul eine spezielle eigenständige Require-Funktion erstellt. Dies ist eine Funktion, die wir alle brauchen und mit der wir vertraut sind. Die Funktion selbst ist nur ein Paket in Module.require und enthält auch einige wenig bekannte Hilfsmethoden, die für uns einfach zu verwenden sind:
· require(): Laden Sie ein externes Modul
· require.resolve(): Lösen Sie einen Modulnamen in seinen absoluten Pfad
auf
· require.main:Hauptmodul
· require.cache: alle zwischengespeicherten Module
· ·require.extensions: Die verfügbaren Kompilierungsmethoden für jeden gültigen Dateityp entsprechend seiner Erweiterung
Sobald „require“ bereit ist, wird der gesamte geladene Quellcode in einer neuen Funktion gekapselt, die „require“, „module“, „exports“ und alle anderen offengelegten Variablen als Parameter akzeptieren kann. Dies ist eine Funktion, die ausschließlich zur Kapselung des Moduls erstellt wurde, um Konflikte mit der Node.js-Umgebung zu verhindern.
Fazit
Wir haben also den gesamten Anforderungscode verstanden und haben ein vorläufiges Verständnis dafür, wie er funktioniert.
Wenn Sie das alles befolgt haben, sind Sie bereit für das letzte Geheimnis: require('module'). Richtig, das Modulsystem selbst kann über das Modulsystem geladen werden. Beginn. Das mag seltsam klingen, aber es ermöglicht dem Benutzerraum, mit dem Modulladesystem zu interagieren, ohne sich mit dem Kern von Node.j befassen zu müssen. Beliebte Module sind so aufgebaut. [2]
Wenn Sie mehr wissen möchten, schauen Sie sich selbst den Quellcode von module.js an. Es gibt genug Dinge, die Ihnen für eine Weile Kopfschmerzen bereiten. Kann mir der erste sagen, was „NODE_MODULE_CONTEXTS“ ist und warum es hinzugefügt wird und wer es hinzufügt, kann Bonuspunkte erhalten :)
[1] Die Methode module._compile wird nur zum Ausführen von JavaScript-Dateien verwendet. JSON-Dateien müssen über JSON.parse() analysiert und
zurückgegeben werden[2] Beide Module basieren jedoch auf privaten Modulmethoden wie Module._resolveLookupPaths und Module._findPath. Man könnte meinen, dass es nicht viel besser ist...