Baseline Widely available *
Die import()
-Syntax, oft als dynamischer Import bezeichnet, ist ein funktionsähnlicher Ausdruck, der es ermöglicht, ein ECMAScript-Modul asynchron und dynamisch in eine potenziell Nicht-Modulumgebung zu laden.
Im Gegensatz zum deklarativen Pendant werden dynamische Importe nur bei Bedarf ausgewertet und erlauben eine gröÃere syntaktische Flexibilität.
Syntaximport(moduleName)
import(moduleName, options)
Der import()
-Aufruf ist eine Syntax, die einem Funktionsaufruf ähnelt, jedoch ist import
selbst ein Schlüsselwort und keine Funktion. Sie können es nicht wie const myImport = import
aliasieren, da dies einen SyntaxError
werfen wird.
AbschlieÃende Kommata sind nur erlaubt, wenn die Laufzeit auch options
unterstützt. Ãberprüfen Sie die Browser-Kompatibilität.
moduleName
Das Modul, von dem importiert werden soll. Die Bewertung des Bezeichners ist host-spezifisch, folgt jedoch immer dem gleichen Algorithmus wie bei statischen Import-Deklarationen.
options
Ein Objekt, das Import-Optionen enthält. Der folgende Schlüssel wird erkannt:
with
Die Import-Attribute.
Gibt ein Promise zurück, das:
moduleName
enthält.moduleName
einen Fehler wirft, mit diesem Fehler abgelehnt wird.Error
, während alle Browser TypeError
verwenden). Häufige Ursachen können sein:
Hinweis: import()
wirft niemals synchron einen Fehler.
Die Import-Deklarationssyntax (import something from "somewhere"
) ist statisch und das importierte Modul wird immer zur Ladezeit ausgewertet. Dynamische Importe ermöglichen es, die syntaktische Starrheit von Import-Deklarationen zu umgehen und ein Modul bedingt oder auf Abruf zu laden. Hier sind einige Gründe, warum Sie einen dynamischen Import verwenden könnten:
eval
oder eine Skript-Datei).Verwenden Sie dynamische Importe nur, wenn es notwendig ist. Die statische Form ist vorzuziehen, um initiale Abhängigkeiten zu laden, und kann besser von statischen Analysetools und Tree Shaking profitieren.
Wenn Ihre Datei nicht als Modul ausgeführt wird (wenn sie in einer HTML-Datei referenziert wird, muss das Skripttag type="module"
haben), können Sie keine statischen Import-Deklarationen verwenden. Andererseits ist die asynchrone dynamische Import-Syntax immer verfügbar, sodass Sie Module in Nicht-Modulumgebungen importieren können.
Der options
-Parameter ermöglicht verschiedene Arten von Importoptionen. Zum Beispiel Import-Attribute:
import("./data.json", { with: { type: "json" } });
Dynamischer Modulimport ist nicht in allen Ausführungskontexten erlaubt. Zum Beispiel kann import()
im Haupt-Thread, einem geteilten Worker oder einem dedizierten Worker verwendet werden, wird jedoch einen Fehler werfen, wenn er innerhalb eines Service Worker oder eines Worklet aufgerufen wird.
Ein Modul-Namensraum-Objekt ist ein Objekt, das alle Exporte aus einem Modul beschreibt. Es ist ein statisches Objekt, das erstellt wird, wenn das Modul ausgewertet wird. Es gibt zwei Möglichkeiten, auf das Modul-Namensraum-Objekt eines Moduls zuzugreifen: durch einen Namensraum-Import (import * as name from moduleName
) oder durch den Erfüllungswert eines dynamischen Imports.
Das Modul-Namensraum-Objekt ist ein versiegeltes Objekt mit null
-Prototyp. Das bedeutet, alle String-Schlüssel des Objekts entsprechen den Exporten des Moduls und es gibt niemals zusätzliche Schlüssel. Alle Schlüssel sind durchlässig in lexikografischer Reihenfolge (d.h. das Standardverhalten von Array.prototype.sort()
), wobei der Standardexport als Schlüssel default
verfügbar ist. Zusätzlich hat das Modul-Namensraum-Objekt eine [Symbol.toStringTag]
-Eigenschaft mit dem Wert "Module"
, die in Object.prototype.toString()
verwendet wird.
Die String-Eigenschaften sind nicht konfigurierbar und beschreibbar, wenn Sie Object.getOwnPropertyDescriptors()
verwenden, um ihre Deskriptoren zu erhalten. Sie sind jedoch effektiv schreibgeschützt, da Sie einer Eigenschaft keinen neuen Wert zuweisen können. Dieses Verhalten spiegelt die Tatsache wider, dass statische Importe "Live-Bindungen" erstellen â die Werte können vom Modul, das sie exportiert, neu zugewiesen werden, aber nicht von dem Modul, das sie importiert. Die Beschreibbarkeit der Eigenschaften spiegelt die Möglichkeit wider, dass sich die Werte ändern, da nicht konfigurierbare und nicht schreibbare Eigenschaften konstant sein müssen. Zum Beispiel können Sie den exportierten Wert einer Variablen neu zuweisen, und der neue Wert kann im Modul-Namensraum-Objekt beobachtet werden.
Jeder (normalisierte) Modulbezeichner entspricht einem einzigartigen Modul-Namensraum-Objekt, daher ist Folgendes im Allgemeinen wahr:
import * as mod from "/my-module.js";
import("/my-module.js").then((mod2) => {
console.log(mod === mod2); // true
});
AuÃer in einem kuriosen Fall: Da ein Promise nie zu einem Thenable erfüllt, wird die Funktion then()
, die aus dem Modul my-module.js
exportiert wird, automatisch aufgerufen, wenn das Promise des dynamischen Imports erfüllt ist, als Teil des Promise-Auflösungsprozesses.
// my-module.js
export function then(resolve) {
console.log("then() called");
resolve(1);
}
// main.js
import * as mod from "/my-module.js";
import("/my-module.js").then((mod2) => {
// Logs "then() called"
console.log(mod === mod2); // false
});
Warnung: Exportieren Sie keine Funktion namens then()
aus einem Modul. Dies wird dazu führen, dass das Modul unterschiedlich verhält, wenn es dynamisch importiert wird, im Vergleich zu einem statischen Import.
Dieses aggressive Caching stellt sicher, dass ein Stück JavaScript-Code nie mehr als einmal ausgeführt wird, selbst wenn es mehrfach importiert wird. Zukünftige Importe führen nicht einmal zu HTTP-Anfragen oder Festplattenzugriffen. Wenn Sie ein Modul neu importieren und neu auswerten müssen, ohne die gesamte JavaScript-Umgebung neu zu starten, könnten Sie einen einzigartigen Query-Parameter im Modulbezeichner verwenden. Dies funktioniert auch in Nicht-Browser-Laufzeitumgebungen, die URL-Bezeichner unterstützen.
import(`/my-module.js?t=${Date.now()}`);
Beachten Sie, dass dies in einer lang laufenden Anwendung zu Speicherlecks führen kann, da die Engine keine Modul-Namensraum-Objekte sicher garbage-colleten kann. Derzeit gibt es keine Möglichkeit, den Cache von Modul-Namensraum-Objekten manuell zu leeren.
Das Caching von Modul-Namensraum-Objekten gilt nur für Module, die erfolgreich geladen und verbunden sind. Ein Modul wird in drei Schritten importiert: Laden (Abrufen des Moduls), Verbinden (meistens Parsen des Moduls) und Auswerten (Ausführen des geparsten Codes). Nur Auswertungsfehler werden zwischengespeichert; wenn ein Modul nicht geladen oder verbunden werden kann, kann der nächste Import versuchen, das Modul erneut zu laden und zu verbinden. Der Browser kann das Ergebnis der Abrufoperation zwischenspeichern oder nicht, sollte aber den typischen HTTP-Semantiken folgen, sodass das Handling solcher Netzwerkausfälle sich nicht vom Handling von fetch()
-Ausfällen unterscheiden sollte.
(async () => {
if (somethingIsTrue) {
// import module for side effects
await import("/modules/my-module.js");
}
})();
Wenn Ihr Projekt Pakete verwendet, die ESM exportieren, können Sie diese auch nur für Nebeneffekte importieren. Dies wird den Code in der Package-Entry-Point-Datei (und allen von ihm importierten Dateien) nur ausführen.
StandardimporteWenn Sie das importierte Modul-Namensraum-Objekt destrukturieren, müssen Sie den default
-Schlüssel umbenennen, da default
ein reserviertes Wort ist.
(async () => {
if (somethingIsTrue) {
const {
default: myDefault,
foo,
bar,
} = await import("/modules/my-module.js");
}
})();
Import bei Bedarf als Reaktion auf Benutzeraktionen
In diesem Beispiel wird gezeigt, wie Funktionalität basierend auf einer Benutzeraktion, in diesem Fall einem Button-Klick, auf einer Seite geladen und eine Funktion innerhalb dieses Moduls aufgerufen wird. Dies ist nicht die einzige Möglichkeit, diese Funktionalität zu implementieren. Die import()
-Funktion unterstützt auch await
.
const main = document.querySelector("main");
for (const link of document.querySelectorAll("nav > a")) {
link.addEventListener("click", (e) => {
e.preventDefault();
import("/modules/my-module.js")
.then((module) => {
module.loadPageInto(main);
})
.catch((err) => {
main.textContent = err.message;
});
});
}
Module basierend auf der Umgebung importieren
Bei Prozessen wie der serverseitigen Darstellung müssen Sie möglicherweise unterschiedliche Logik auf dem Server oder im Browser laden, weil sie mit verschiedenen globalen Objekten oder Modulen interagieren (zum Beispiel hat Browser-Code Zugriff auf Web-APIs wie document
und navigator
, während Server-Code Zugriff auf das Dateisystem des Servers hat). Dies kann mit einem bedingten dynamischen Import erreicht werden.
let myModule;
if (typeof window === "undefined") {
myModule = await import("module-used-on-server");
} else {
myModule = await import("module-used-in-browser");
}
Module mit einem nicht literalen Bezeichner importieren
Dynamische Importe ermöglichen jeden Ausdruck als Modulbezeichner, nicht notwendigerweise String-Literale.
Hier laden wir 10 Module, /modules/module-0.js
, /modules/module-1.js
usw. gleichzeitig, und rufen die load
-Funktionen auf, die jedes von ihnen exportiert.
Promise.all(
Array.from({ length: 10 }).map(
(_, index) => import(`/modules/module-${index}.js`),
),
).then((modules) => modules.forEach((module) => module.load()));
Spezifikationen Browser-Kompatibilität Siehe auch
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4