Was passiert, wenn ein JS-Modul zweimal importiert wird?

Beginnen wir diesen Artikel mit einer Frage. Das ES2015-Modul incremententhält den folgenden Code:

// increment.js
let counter = 0;
counter++;

export default counter;

In einem anderen Modul, das wir aufrufen werden consumer, wird das obige Modul zweimal importiert:

// consumer.js
import counter1 from './increment';
import counter2 from './increment';

counter1; // => ???
counter2; // => ???

Und jetzt eigentlich eine Frage. Was kommt in die Variablen counter1und counter2nach dem Modul consumer? Um diese Frage zu beantworten, müssen Sie wissen, wie JavaScript Module ausführt und wie sie importiert werden.





Modulausführung


Um zu verstehen, wie die internen JavaScript-Mechanismen funktionieren, ist es hilfreich, die Spezifikation zu untersuchen .

Gemäß der Spezifikation wird jedes JavaScript - Modul mit einer zugehörigen Modul Bilanz Einheit . Dieser Eintrag verfügt über eine Methode Evaluate(), die das Modul ausführt:

Wenn dieses Modul bereits erfolgreich ausgeführt wurde, geben Sie undefined zurück. [...]. Andernfalls führen Sie transitiv alle Abhängigkeiten dieses Moduls aus und führen Sie dann dieses Modul aus.
Infolgedessen stellt sich heraus, dass dasselbe Modul nur einmal ausgeführt wird.

Leider ist das, was Sie zur Beantwortung unserer Frage wissen müssen, nicht darauf beschränkt. So stellen Sie sicher, dass die Anweisung aufgerufen wirdimport Wenn Sie dieselben Pfade verwenden, wird dasselbe Modul zurückgegeben.

Importbefehle zulassen


Die abstrakte Operation HostResolveImportedModule () ist dafür verantwortlich, den Pfad zum Modul ( Bezeichner ) einem bestimmten Modul zuzuordnen . Der Modul-Importcode sieht folgendermaßen aus:

import module from 'path';

In der Spezifikation heißt es dazu:

Eine Implementierung von HostResolveImportedModule muss die folgenden Anforderungen erfüllen:

  • Der normale Rückgabewert sollte eine Instanz einer bestimmten Unterklasse von Module Record sein.
  • Wenn die Moduldatensatzentität, die dem Paar referenziert, das auf ScriptOrModule verweist, nicht vorhanden ist oder eine solche Entität nicht erstellt werden kann, wird eine Ausnahme ausgelöst.
  • Jedes Mal, wenn diese Operation aufgerufen wird und ein bestimmtes Paar von referencingScriptOrModule-Spezifizierern als Argumente an sie übergeben wird, sollte sie im Falle ihrer üblichen Ausführung dieselbe Instanz der Module Record-Entität zurückgeben.

Betrachten Sie dies nun verständlicher.

HostResolveImportedModule(referencingScriptOrModule, specifier)- eine abstrakte Operation kehrt dass das Modul mit einem Paar von Parametern entspricht referencingScriptOrModule, specifier:

  • Der Parameter referencingScriptOrModuleist das aktuelle Modul, dh das zu importierende Modul.
  • Ein Parameter specifierist eine Zeichenfolge, die dem Modulpfad in der Anweisung entspricht import.

Am Ende der Beschreibung HostResolveImportedModule()wird angegeben, dass beim Importieren von Modulen, die demselben Pfad entsprechen, dasselbe Modul importiert wird:

import moduleA from 'path';
import moduleB from 'path';
import moduleC from 'path';

// moduleA, moduleB  moduleC -    

moduleA === moduleB; // => true
moduleB === moduleC; // => true

Interessanterweise gibt die Spezifikation an, dass der Host (Browser, Node.js-Umgebung im Allgemeinen - alles, was versucht, JavaScript-Code auszuführen) eine bestimmte Implementierung bereitstellen sollte HostResolveImportedModule().

Antworten


Nach sorgfältigem Lesen der Spezifikation wird deutlich, dass JavaScript-Module beim Import nur einmal ausgeführt werden. Beim Importieren eines Moduls über denselben Pfad wird dieselbe Instanz des Moduls zurückgegeben.

Kommen wir zurück zu unserer Frage.

Ein Modul wird incrementimmer nur einmal ausgeführt:

// increment.js
let counter = 0;
counter++;

export default counter;

Unabhängig davon, wie oft ein Modul importiert wurde increment, wird ein Ausdruck counter++nur einmal ausgewertet. Eine Variable, counterdie mit dem Standardexportmechanismus exportiert wird, ist wichtig 1.

Schauen Sie sich nun das Modul an consumer:

// consumer.js
import counter1 from './increment';
import counter2 from './increment';

counter1; // => 1
counter2; // => 1

Die Befehle import counter1 from './increment'und import counter2 from './increment'verwenden den gleichen Pfad - './increment'. Als Ergebnis stellt sich heraus, dass dieselbe Instanz des Moduls importiert wird.

Es stellt sich heraus, dass der gleiche Wert 1 in die Variablen counter1und counter2in geschrieben wird consumer.

Zusammenfassung


Nachdem wir eine einfache Frage untersucht hatten, konnten wir mehr darüber erfahren, wie JavaScript-Module ausgeführt und importiert werden.

Die beim Importieren von Modulen verwendeten Regeln sind recht einfach: Das gleiche Modul wird nur einmal ausgeführt. Mit anderen Worten, was im Umfang der Modulebene liegt, wird nur einmal ausgeführt. Wenn ein Modul, das bereits einmal ausgeführt wurde, erneut importiert wird, wird es nicht erneut ausgeführt. Beim Importieren eines Moduls wird anhand der Ergebnisse einer vorherigen Sitzung ermittelt, was genau exportiert wird.

Wenn ein Modul mehrmals importiert wird, der Modulspezifizierer (Pfad dazu) jedoch gleich bleibt, stellt die JavaScript-Spezifikation sicher, dass dieselbe Modulinstanz importiert wird.

Liebe Leser! Wie oft lesen Sie die JavaScript-Spezifikation, um die Funktionsweise bestimmter Sprachkonstrukte herauszufinden?


All Articles