VM (JavaScript ausführen)
[Stabil: 2 - Stabil]
Stabil: 2 Stabilität: 2 - Stabil
Quellcode: lib/vm.js
Das node:vm
-Modul ermöglicht das Kompilieren und Ausführen von Code innerhalb von V8 Virtual Machine-Kontexten.
Das Modul node:vm
ist kein Sicherheitsmechanismus. Verwenden Sie es nicht, um nicht vertrauenswürdigen Code auszuführen.
JavaScript-Code kann kompiliert und sofort ausgeführt oder kompiliert, gespeichert und später ausgeführt werden.
Ein häufiger Anwendungsfall ist das Ausführen des Codes in einem anderen V8-Kontext. Dies bedeutet, dass der aufgerufene Code ein anderes globales Objekt hat als der aufrufende Code.
Man kann den Kontext durch Kontextualisierung eines Objekts bereitstellen. Der aufgerufene Code behandelt jede Eigenschaft im Kontext wie eine globale Variable. Alle Änderungen an globalen Variablen, die durch den aufgerufenen Code verursacht werden, spiegeln sich im Kontextobjekt wider.
const vm = require('node:vm')
const x = 1
const context = { x: 2 }
vm.createContext(context) // Kontextualisiert das Objekt.
const code = 'x += 40; var y = 17;'
// `x` und `y` sind globale Variablen im Kontext.
// Anfangs hat x den Wert 2, weil dies der Wert von context.x ist.
vm.runInContext(code, context)
console.log(context.x) // 42
console.log(context.y) // 17
console.log(x) // 1; y ist nicht definiert.
Klasse: vm.Script
Hinzugefügt in: v0.3.1
Instanzen der Klasse vm.Script
enthalten vorkompilierte Skripte, die in bestimmten Kontexten ausgeführt werden können.
new vm.Script(code[, options])
[Verlauf]
Version | Änderungen |
---|---|
v21.7.0, v20.12.0 | Unterstützung für vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER hinzugefügt. |
v17.0.0, v16.12.0 | Unterstützung für Importattribute für den Parameter importModuleDynamically hinzugefügt. |
v10.6.0 | produceCachedData ist zugunsten von script.createCachedData() veraltet. |
v5.7.0 | Die Optionen cachedData und produceCachedData werden jetzt unterstützt. |
v0.3.1 | Hinzugefügt in: v0.3.1 |
code
<string> Der zu kompilierende JavaScript-Code.options
<Object> | <string>filename
<string> Gibt den Dateinamen an, der in Stacktraces verwendet wird, die von diesem Skript erzeugt werden. Standard:'evalmachine.\<anonymous\>'
.lineOffset
<number> Gibt den Zeilennummernversatz an, der in Stacktraces angezeigt wird, die von diesem Skript erzeugt werden. Standard:0
.columnOffset
<number> Gibt den Spaltennummernversatz der ersten Zeile an, der in Stacktraces angezeigt wird, die von diesem Skript erzeugt werden. Standard:0
.cachedData
<Buffer> | <TypedArray> | <DataView> Stellt optional einenBuffer
oderTypedArray
oderDataView
mit den Code-Cache-Daten von V8 für die bereitgestellte Quelle bereit. Wenn angegeben, wird der Wert voncachedDataRejected
je nach Akzeptanz der Daten durch V8 entweder auftrue
oderfalse
gesetzt.produceCachedData
<boolean> Wenntrue
und keinecachedData
vorhanden ist, versucht V8, Code-Cache-Daten fürcode
zu erzeugen. Bei Erfolg wird einBuffer
mit den Code-Cache-Daten von V8 erzeugt und in der EigenschaftcachedData
der zurückgegebenenvm.Script
-Instanz gespeichert. Der Wert voncachedDataProduced
wird je nachdem, ob Code-Cache-Daten erfolgreich erzeugt wurden, entweder auftrue
oderfalse
gesetzt. Diese Option ist zugunsten vonscript.createCachedData()
veraltet. Standard:false
.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Wird verwendet, um anzugeben, wie die Module während der Auswertung dieses Skripts geladen werden sollen, wennimport()
aufgerufen wird. Diese Option ist Teil der experimentellen Modul-API. Wir empfehlen nicht, sie in einer Produktionsumgebung zu verwenden. Ausführliche Informationen finden Sie unter Unterstützung von dynamischemimport()
in Kompilierungs-APIs.
Wenn options
ein String ist, dann gibt es den Dateinamen an.
Das Erstellen eines neuen vm.Script
-Objekts kompiliert code
, führt es aber nicht aus. Das kompilierte vm.Script
kann später mehrmals ausgeführt werden. Der code
ist an kein globales Objekt gebunden, sondern wird vor jeder Ausführung, nur für diese Ausführung, gebunden.
script.cachedDataRejected
Hinzugefügt in: v5.7.0
Wenn cachedData
zur Erstellung von vm.Script
bereitgestellt wird, wird dieser Wert entweder auf true
oder false
gesetzt, abhängig von der Akzeptanz der Daten durch V8. Andernfalls ist der Wert undefined
.
script.createCachedData()
Hinzugefügt in: v10.6.0
- Gibt zurück: <Buffer>
Erstellt einen Code-Cache, der mit der Option cachedData
des Script
-Konstruktors verwendet werden kann. Gibt einen Buffer
zurück. Diese Methode kann jederzeit und beliebig oft aufgerufen werden.
Der Code-Cache des Script
enthält keine in JavaScript beobachtbaren Zustände. Der Code-Cache kann zusammen mit dem Skript-Quellcode sicher gespeichert und zum Erstellen neuer Script
-Instanzen mehrfach verwendet werden.
Funktionen im Script
-Quellcode können als verzögert kompilierbar markiert werden und werden bei der Konstruktion des Script
nicht kompiliert. Diese Funktionen werden kompiliert, wenn sie das erste Mal aufgerufen werden. Der Code-Cache serialisiert die Metadaten, die V8 aktuell über das Script
kennt und die es verwenden kann, um zukünftige Kompilierungen zu beschleunigen.
const script = new vm.Script(`
function add(a, b) {
return a + b;
}
const x = add(1, 2);
`)
const cacheWithoutAdd = script.createCachedData()
// In `cacheWithoutAdd` wird die Funktion `add()` für die vollständige Kompilierung
// beim Aufruf markiert.
script.runInThisContext()
const cacheWithAdd = script.createCachedData()
// `cacheWithAdd` enthält die vollständig kompilierte Funktion `add()`.
script.runInContext(contextifiedObject[, options])
[Verlauf]
Version | Änderungen |
---|---|
v6.3.0 | Die Option breakOnSigint wird jetzt unterstützt. |
v0.3.1 | Hinzugefügt in: v0.3.1 |
contextifiedObject
<Object> Ein kontextualisiertes Objekt, das von der Methodevm.createContext()
zurückgegeben wird.options
<Object>displayErrors
<boolean> Wenntrue
, wird die Codezeile, die den Fehler verursacht, an die Stack-Trace angehängt, wenn einError
beim Kompilieren descode
auftritt. Standard:true
.timeout
<integer> Gibt die Anzahl der Millisekunden an, diecode
ausgeführt werden soll, bevor die Ausführung beendet wird. Wenn die Ausführung beendet wird, wird einError
ausgelöst. Dieser Wert muss eine strikt positive Ganzzahl sein.breakOnSigint
<boolean> Wenntrue
, wird der Empfang vonSIGINT
(+) die Ausführung beenden und einenError
auslösen. Vorhandene Handler für das Ereignis, die überprocess.on('SIGINT')
angehängt wurden, sind während der Skriptausführung deaktiviert, funktionieren aber danach weiter. Standard:false
.
Gibt zurück: <any> Das Ergebnis der allerletzten Anweisung, die im Skript ausgeführt wurde.
Führt den kompilierten Code, der vom vm.Script
-Objekt enthalten ist, im angegebenen contextifiedObject
aus und gibt das Ergebnis zurück. Der ausgeführte Code hat keinen Zugriff auf den lokalen Bereich.
Das folgende Beispiel kompiliert Code, der eine globale Variable inkrementiert, den Wert einer anderen globalen Variable setzt und dann den Code mehrmals ausführt. Die globalen Variablen sind im context
-Objekt enthalten.
const vm = require('node:vm')
const context = {
animal: 'cat',
count: 2,
}
const script = new vm.Script('count += 1; name = "kitty";')
vm.createContext(context)
for (let i = 0; i < 10; ++i) {
script.runInContext(context)
}
console.log(context)
// Gibt aus: { animal: 'cat', count: 12, name: 'kitty' }
Die Verwendung der Optionen timeout
oder breakOnSigint
führt zu neuen Event-Loops und entsprechenden Threads, die einen nicht-null Leistungs-Overhead haben.
script.runInNewContext([contextObject[, options]])
[History]
Version | Änderungen |
---|---|
v22.8.0, v20.18.0 | Das Argument contextObject akzeptiert jetzt vm.constants.DONT_CONTEXTIFY . |
v14.6.0 | Die Option microtaskMode wird jetzt unterstützt. |
v10.0.0 | Die Option contextCodeGeneration wird jetzt unterstützt. |
v6.3.0 | Die Option breakOnSigint wird jetzt unterstützt. |
v0.3.1 | Hinzugefügt in: v0.3.1 |
contextObject
<Object> | <vm.constants.DONT_CONTEXTIFY> | <undefined> Entwedervm.constants.DONT_CONTEXTIFY
oder ein Objekt, das kontextualisiert wird. Wennundefined
, wird ein leeres kontextualisiertes Objekt zur Abwärtskompatibilität erstellt.options
<Object>displayErrors
<boolean> Wenntrue
, wird im Falle einesError
beim Kompilieren descode
die Fehler verursachende Codezeile an den Stacktrace angehängt. Standard:true
.timeout
<integer> Gibt die Anzahl der Millisekunden an, diecode
ausgeführt wird, bevor die Ausführung beendet wird. Wenn die Ausführung beendet wird, wird einError
ausgelöst. Dieser Wert muss eine streng positive Ganzzahl sein.breakOnSigint
<boolean> Wenntrue
, wird das Empfangen vonSIGINT
(+) die Ausführung beenden und einenError
auslösen. Vorhandene Handler für das Ereignis, die überprocess.on('SIGINT')
angehängt wurden, werden während der Skriptausführung deaktiviert, funktionieren aber danach weiter. Standard:false
.contextName
<string> Für Menschen lesbarer Name des neu erstellten Kontexts. Standard:'VM Context i'
, wobeii
ein aufsteigender numerischer Index des erstellten Kontexts ist.contextOrigin
<string> Herkunft, die dem neu erstellten Kontext zu Anzeigezwecken entspricht. Die Herkunft sollte wie eine URL formatiert sein, jedoch nur mit dem Schema, dem Host und dem Port (falls erforderlich), wie der Wert der Eigenschafturl.origin
einesURL
-Objekts. Insbesondere sollte diese Zeichenfolge den abschließenden Schrägstrich weglassen, da dieser einen Pfad kennzeichnet. Standard:''
.contextCodeGeneration
<Object>strings
<boolean> Wenn auf "false" gesetzt, lösen alle Aufrufe voneval
oder Funktionskonstruktoren (Function
,GeneratorFunction
usw.) einenEvalError
aus. Standard:true
.wasm
<boolean> Wenn auf "false" gesetzt, löst jeder Versuch, ein WebAssembly-Modul zu kompilieren, einenWebAssembly.CompileError
aus. Standard:true
.microtaskMode
<string> Wenn aufafterEvaluate
gesetzt, werden Mikrotasks (Aufgaben, die überPromise
s undasync function
s geplant werden) unmittelbar nach der Ausführung des Skripts ausgeführt. Sie sind in diesem Fall in den Bereichentimeout
undbreakOnSigint
enthalten.
Gibt zurück: <any> Das Ergebnis der letzten Anweisung, die im Skript ausgeführt wurde.
Diese Methode ist eine Abkürzung für script.runInContext(vm.createContext(options), options)
. Sie erledigt mehrere Dinge gleichzeitig:
Das folgende Beispiel kompiliert Code, der eine globale Variable setzt, und führt den Code dann mehrfach in verschiedenen Kontexten aus. Die globalen Variablen werden in jedem einzelnen context
gesetzt und darin enthalten.
const vm = require('node:vm')
const script = new vm.Script('globalVar = "set"')
const contexts = [{}, {}, {}]
contexts.forEach(context => {
script.runInNewContext(context)
})
console.log(contexts)
// Prints: [{ globalVar: 'set' }, { globalVar: 'set' }, { globalVar: 'set' }]
// Dies würde einen Fehler auslösen, wenn der Kontext aus einem kontextualisierten Objekt erstellt wird.
// vm.constants.DONT_CONTEXTIFY ermöglicht das Erstellen von Kontexten mit normalen
// globalen Objekten, die eingefroren werden können.
const freezeScript = new vm.Script('Object.freeze(globalThis); globalThis;')
const frozenContext = freezeScript.runInNewContext(vm.constants.DONT_CONTEXTIFY)
script.runInThisContext([options])
[History]
Version | Änderungen |
---|---|
v6.3.0 | Die Option breakOnSigint wird jetzt unterstützt. |
v0.3.1 | Hinzugefügt in: v0.3.1 |
options
<Object>displayErrors
<boolean> Wenntrue
, wird im Falle einesError
beim Kompilieren descode
, die Codezeile, die den Fehler verursacht, an den Stack-Trace angehängt. Standard:true
.timeout
<integer> Gibt die Anzahl der Millisekunden an, die dercode
vor dem Beenden der Ausführung ausgeführt werden soll. Wenn die Ausführung beendet wird, wird einError
ausgelöst. Dieser Wert muss eine strikt positive Ganzzahl sein.breakOnSigint
<boolean> Wenntrue
, beendet das Empfangen vonSIGINT
(+) die Ausführung und löst einenError
aus. Vorhandene Handler für das Ereignis, die überprocess.on('SIGINT')
angehängt wurden, werden während der Skriptausführung deaktiviert, funktionieren aber danach weiter. Standard:false
.
Gibt zurück: <any> Das Ergebnis der letzten Anweisung, die im Skript ausgeführt wurde.
Führt den kompilierten Code, der von dem vm.Script
enthalten ist, im Kontext des aktuellen global
Objekts aus. Der ausgeführte Code hat keinen Zugriff auf den lokalen Scope, aber hat Zugriff auf das aktuelle global
Objekt.
Das folgende Beispiel kompiliert Code, der eine global
Variable inkrementiert, und führt diesen Code dann mehrmals aus:
const vm = require('node:vm')
global.globalVar = 0
const script = new vm.Script('globalVar += 1', { filename: 'myfile.vm' })
for (let i = 0; i < 1000; ++i) {
script.runInThisContext()
}
console.log(globalVar)
// 1000
script.sourceMapURL
Hinzugefügt in: v19.1.0, v18.13.0
Wenn das Skript aus einer Quelle kompiliert wird, die einen Source-Map-Magic-Kommentar enthält, wird diese Eigenschaft auf die URL der Source-Map gesetzt.
import vm from 'node:vm'
const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`)
console.log(script.sourceMapURL)
// Gibt aus: sourcemap.json
const vm = require('node:vm')
const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`)
console.log(script.sourceMapURL)
// Gibt aus: sourcemap.json
Klasse: vm.Module
Hinzugefügt in: v13.0.0, v12.16.0
[Stabil: 1 - Experimentell]
Stabil: 1 Stabilität: 1 - Experimentell
Diese Funktion ist nur mit dem aktivierten Befehlsflag --experimental-vm-modules
verfügbar.
Die Klasse vm.Module
bietet eine Low-Level-Schnittstelle zur Verwendung von ECMAScript-Modulen in VM-Kontexten. Sie ist das Gegenstück zur Klasse vm.Script
, das die Module Records, wie in der ECMAScript-Spezifikation definiert, genau widerspiegelt.
Im Gegensatz zu vm.Script
ist jedoch jedes vm.Module
-Objekt ab seiner Erstellung an einen Kontext gebunden. Operationen an vm.Module
-Objekten sind von Natur aus asynchron, im Gegensatz zum synchronen Charakter von vm.Script
-Objekten. Die Verwendung von 'async'-Funktionen kann bei der Manipulation von vm.Module
-Objekten helfen.
Die Verwendung eines vm.Module
-Objekts erfordert drei verschiedene Schritte: Erstellung/Parsen, Verknüpfung und Auswertung. Diese drei Schritte werden im folgenden Beispiel veranschaulicht.
Diese Implementierung liegt auf einer niedrigeren Ebene als der ECMAScript-Modul-Loader. Es gibt auch noch keine Möglichkeit, mit dem Loader zu interagieren, obwohl Unterstützung geplant ist.
import vm from 'node:vm'
const contextifiedObject = vm.createContext({
secret: 42,
print: console.log,
})
// Schritt 1
//
// Erstellen Sie ein Modul, indem Sie ein neues `vm.SourceTextModule`-Objekt konstruieren.
// Dies parst den bereitgestellten Quelltext und wirft einen `SyntaxError`, falls etwas
// schief geht. Standardmäßig wird ein Modul im obersten Kontext erstellt. Hier
// geben wir jedoch `contextifiedObject` als Kontext an, zu dem dieses Modul gehört.
//
// Hier versuchen wir, den Standardexport aus dem Modul "foo" zu erhalten und
// ihn in die lokale Bindung "secret" einzufügen.
const bar = new vm.SourceTextModule(
`
import s from 'foo';
s;
print(s);
`,
{ context: contextifiedObject }
)
// Schritt 2
//
// "Verknüpfen" Sie die importierten Abhängigkeiten dieses Moduls damit.
//
// Der bereitgestellte Linker-Callback (der "Linker") akzeptiert zwei Argumente:
// das übergeordnete Modul (`bar` in diesem Fall) und die Zeichenkette, die die
// Spezifikation des importierten Moduls ist. Der Callback wird erwartet, ein
// Modul zurückzugeben, das der bereitgestellten Spezifikation entspricht, mit
// bestimmten Anforderungen, die in `module.link()` dokumentiert sind.
//
// Wenn die Verknüpfung für das zurückgegebene Modul noch nicht begonnen hat, wird
// derselbe Linker-Callback für das zurückgegebene Modul aufgerufen.
//
// Sogar Module der obersten Ebene ohne Abhängigkeiten müssen explizit verknüpft
// werden. Der bereitgestellte Callback würde jedoch nie aufgerufen werden.
//
// Die Methode link() gibt eine Promise zurück, die aufgelöst wird, wenn alle von
// dem Linker zurückgegebenen Promises aufgelöst werden.
//
// Hinweis: Dies ist ein konstruiertes Beispiel, da die Linker-Funktion jedes Mal
// ein neues "foo"-Modul erstellt, wenn sie aufgerufen wird. In einem vollwertigen
// Modulsystem würde wahrscheinlich ein Cache verwendet, um doppelte Module zu
// vermeiden.
async function linker(specifier, referencingModule) {
if (specifier === 'foo') {
return new vm.SourceTextModule(
`
// Die Variable "secret" bezieht sich auf die globale Variable, die wir beim
// Erstellen des Kontexts zu "contextifiedObject" hinzugefügt haben.
export default secret;
`,
{ context: referencingModule.context }
)
// Die Verwendung von `contextifiedObject` anstelle von
// `referencingModule.context` würde hier auch funktionieren.
}
throw new Error(`Kann Abhängigkeit nicht auflösen: ${specifier}`)
}
await bar.link(linker)
// Schritt 3
//
// Werten Sie das Modul aus. Die Methode evaluate() gibt eine Promise zurück, die
// aufgelöst wird, nachdem das Modul die Auswertung abgeschlossen hat.
// Gibt 42 aus.
await bar.evaluate()
const vm = require('node:vm')
const contextifiedObject = vm.createContext({
secret: 42,
print: console.log,
})
;(async () => {
// Schritt 1
//
// Erstellen Sie ein Modul, indem Sie ein neues `vm.SourceTextModule`-Objekt konstruieren.
// Dies parst den bereitgestellten Quelltext und wirft einen `SyntaxError`, falls etwas
// schief geht. Standardmäßig wird ein Modul im obersten Kontext erstellt. Hier
// geben wir jedoch `contextifiedObject` als Kontext an, zu dem dieses Modul gehört.
//
// Hier versuchen wir, den Standardexport aus dem Modul "foo" zu erhalten und
// ihn in die lokale Bindung "secret" einzufügen.
const bar = new vm.SourceTextModule(
`
import s from 'foo';
s;
print(s);
`,
{ context: contextifiedObject }
)
// Schritt 2
//
// "Verknüpfen" Sie die importierten Abhängigkeiten dieses Moduls damit.
//
// Der bereitgestellte Linker-Callback (der "Linker") akzeptiert zwei Argumente:
// das übergeordnete Modul (`bar` in diesem Fall) und die Zeichenkette, die die
// Spezifikation des importierten Moduls ist. Der Callback wird erwartet, ein
// Modul zurückzugeben, das der bereitgestellten Spezifikation entspricht, mit
// bestimmten Anforderungen, die in `module.link()` dokumentiert sind.
//
// Wenn die Verknüpfung für das zurückgegebene Modul noch nicht begonnen hat, wird
// derselbe Linker-Callback für das zurückgegebene Modul aufgerufen.
//
// Sogar Module der obersten Ebene ohne Abhängigkeiten müssen explizit verknüpft
// werden. Der bereitgestellte Callback würde jedoch nie aufgerufen werden.
//
// Die Methode link() gibt eine Promise zurück, die aufgelöst wird, wenn alle von
// dem Linker zurückgegebenen Promises aufgelöst werden.
//
// Hinweis: Dies ist ein konstruiertes Beispiel, da die Linker-Funktion jedes Mal
// ein neues "foo"-Modul erstellt, wenn sie aufgerufen wird. In einem vollwertigen
// Modulsystem würde wahrscheinlich ein Cache verwendet, um doppelte Module zu
// vermeiden.
async function linker(specifier, referencingModule) {
if (specifier === 'foo') {
return new vm.SourceTextModule(
`
// Die Variable "secret" bezieht sich auf die globale Variable, die wir beim
// Erstellen des Kontexts zu "contextifiedObject" hinzugefügt haben.
export default secret;
`,
{ context: referencingModule.context }
)
// Die Verwendung von `contextifiedObject` anstelle von
// `referencingModule.context` würde hier auch funktionieren.
}
throw new Error(`Kann Abhängigkeit nicht auflösen: ${specifier}`)
}
await bar.link(linker)
// Schritt 3
//
// Werten Sie das Modul aus. Die Methode evaluate() gibt eine Promise zurück, die
// aufgelöst wird, nachdem das Modul die Auswertung abgeschlossen hat.
// Gibt 42 aus.
await bar.evaluate()
})()
module.dependencySpecifiers
Die Bezeichner aller Abhängigkeiten dieses Moduls. Das zurückgegebene Array ist eingefroren, um Änderungen daran zu verhindern.
Entspricht dem Feld [[RequestedModules]]
von Cyclic Module Records in der ECMAScript-Spezifikation.
module.error
Wenn module.status
'errored'
ist, enthält diese Eigenschaft die Ausnahme, die das Modul während der Auswertung geworfen hat. Wenn der Status etwas anderes ist, führt der Zugriff auf diese Eigenschaft zu einer geworfenen Ausnahme.
Der Wert undefined
kann nicht für Fälle verwendet werden, in denen keine geworfene Ausnahme vorliegt, da dies zu einer möglichen Mehrdeutigkeit mit throw undefined;
führen kann.
Entspricht dem Feld [[EvaluationError]]
von Cyclic Module Records in der ECMAScript-Spezifikation.
module.evaluate([options])
options
<Object>timeout
<integer> Gibt die Anzahl der Millisekunden an, die ausgewertet werden sollen, bevor die Ausführung beendet wird. Wenn die Ausführung unterbrochen wird, wird einError
geworfen. Dieser Wert muss eine strikt positive Ganzzahl sein.breakOnSigint
<boolean> Wenntrue
, beendet das Empfangen vonSIGINT
(+) die Ausführung und wirft einenError
. Vorhandene Handler für das Ereignis, die überprocess.on('SIGINT')
angehängt wurden, werden während der Skriptausführung deaktiviert, funktionieren aber danach weiter. Standard:false
.
Gibt zurück: <Promise> Wird bei Erfolg mit
undefined
erfüllt.
Werten Sie das Modul aus.
Dies muss aufgerufen werden, nachdem das Modul verknüpft wurde; andernfalls wird es abgelehnt. Es könnte auch aufgerufen werden, wenn das Modul bereits ausgewertet wurde. In diesem Fall wird entweder nichts unternommen, wenn die anfängliche Auswertung erfolgreich beendet wurde (module.status
ist 'evaluated'
), oder die Ausnahme, die bei der anfänglichen Auswertung aufgetreten ist, wird erneut geworfen (module.status
ist 'errored'
).
Diese Methode kann nicht aufgerufen werden, während das Modul ausgewertet wird (module.status
ist 'evaluating'
).
Entspricht dem Feld der Evaluate() konkreten Methode von Cyclic Module Records in der ECMAScript-Spezifikation.
module.identifier
Die Kennung des aktuellen Moduls, wie im Konstruktor festgelegt.
module.link(linker)
[Verlauf]
Version | Änderungen |
---|---|
v21.1.0, v20.10.0, v18.19.0 | Die Option extra.assert wird in extra.attributes umbenannt. Der frühere Name wird zur Abwärtskompatibilität weiterhin bereitgestellt. |
linker
<Function>specifier
<string> Der Bezeichner des angeforderten Moduls:referencingModule
<vm.Module> DasModule
-Objekt, für daslink()
aufgerufen wird.extra
<Object>attributes
<Object> Die Daten aus dem Attribut: Gemäß ECMA-262 wird von Hosts erwartet, dass sie einen Fehler auslösen, wenn ein nicht unterstütztes Attribut vorhanden ist.assert
<Object> Alias fürextra.attributes
.Gibt zurück: <vm.Module> | <Promise>
Gibt zurück: <Promise>
Verknüpfen von Modulabhängigkeiten. Diese Methode muss vor der Auswertung aufgerufen werden und kann nur einmal pro Modul aufgerufen werden.
Es wird erwartet, dass die Funktion ein Module
-Objekt oder ein Promise
zurückgibt, das letztendlich in ein Module
-Objekt aufgelöst wird. Das zurückgegebene Module
muss die folgenden zwei Invarianten erfüllen:
- Es muss zum gleichen Kontext wie das übergeordnete
Module
gehören. - Sein
status
darf nicht'errored'
sein.
Wenn der status
des zurückgegebenen Module
'unlinked'
ist, wird diese Methode rekursiv mit derselben bereitgestellten linker
-Funktion für das zurückgegebene Module
aufgerufen.
link()
gibt ein Promise
zurück, das entweder aufgelöst wird, wenn alle Verknüpfungsinstanzen zu einem gültigen Module
aufgelöst werden, oder abgelehnt wird, wenn die Linker-Funktion entweder eine Ausnahme auslöst oder ein ungültiges Module
zurückgibt.
Die Linker-Funktion entspricht in etwa der implementierungsdefinierten abstrakten Operation HostResolveImportedModule in der ECMAScript-Spezifikation, mit einigen wesentlichen Unterschieden:
- Die Linker-Funktion darf asynchron sein, während HostResolveImportedModule synchron ist.
Die tatsächliche HostResolveImportedModule-Implementierung, die während der Modulverknüpfung verwendet wird, ist eine, die die während der Verknüpfung verknüpften Module zurückgibt. Da zu diesem Zeitpunkt bereits alle Module vollständig verknüpft sein sollten, ist die HostResolveImportedModule-Implementierung gemäß Spezifikation vollständig synchron.
Entspricht dem Feld Link() concrete method von Cyclic Module Records in der ECMAScript-Spezifikation.
module.namespace
Das Namespace-Objekt des Moduls. Dies ist erst verfügbar, nachdem die Verknüpfung (module.link()
) abgeschlossen ist.
Entspricht der abstrakten Operation GetModuleNamespace in der ECMAScript-Spezifikation.
module.status
Der aktuelle Status des Moduls. Kann einer der folgenden Werte sein:
'unlinked'
:module.link()
wurde noch nicht aufgerufen.'linking'
:module.link()
wurde aufgerufen, aber noch nicht alle von der Linker-Funktion zurückgegebenen Promises wurden aufgelöst.'linked'
: Das Modul wurde erfolgreich verknüpft, und alle seine Abhängigkeiten sind verknüpft, abermodule.evaluate()
wurde noch nicht aufgerufen.'evaluating'
: Das Modul wird durch einenmodule.evaluate()
auf sich selbst oder ein übergeordnetes Modul ausgewertet.'evaluated'
: Das Modul wurde erfolgreich ausgewertet.'errored'
: Das Modul wurde ausgewertet, aber es wurde eine Ausnahme ausgelöst.
Abgesehen von 'errored'
entspricht diese Statuszeichenkette dem Feld [[Status]]
des Cyclic Module Record der Spezifikation. 'errored'
entspricht in der Spezifikation 'evaluated'
, aber mit [[EvaluationError]]
auf einen Wert gesetzt, der nicht undefined
ist.
Klasse: vm.SourceTextModule
Hinzugefügt in: v9.6.0
[Stabil: 1 - Experimentell]
Stabil: 1 Stabilität: 1 - Experimentell
Diese Funktion ist nur mit dem Befehlsflag --experimental-vm-modules
aktiviert.
- Erweitert: <vm.Module>
Die Klasse vm.SourceTextModule
bietet den Source Text Module Record wie in der ECMAScript-Spezifikation definiert.
new vm.SourceTextModule(code[, options])
[Verlauf]
Version | Änderungen |
---|---|
v17.0.0, v16.12.0 | Unterstützung für Importattribute für den Parameter importModuleDynamically hinzugefügt. |
code
<string> JavaScript-Modulcode zum Parsenoptions
identifier
<string> Zeichenkette, die in Stack-Traces verwendet wird. Standard:'vm:module(i)'
, wobeii
ein kontextspezifischer aufsteigender Index ist.cachedData
<Buffer> | <TypedArray> | <DataView> Stellt einen optionalenBuffer
oderTypedArray
oderDataView
mit den V8-Code-Cache-Daten für die bereitgestellte Quelle bereit. Dercode
muss derselbe sein wie das Modul, aus dem diesecachedData
erstellt wurde.context
<Object> Das kontextualisierte Objekt, das von der Methodevm.createContext()
zurückgegeben wird, um diesesModul
zu kompilieren und auszuwerten. Wenn kein Kontext angegeben ist, wird das Modul im aktuellen Ausführungskontext ausgewertet.lineOffset
<integer> Gibt den Zeilennummern-Offset an, der in den von diesemModul
erzeugten Stack-Traces angezeigt wird. Standard:0
.columnOffset
<integer> Gibt den Spaltennummern-Offset der ersten Zeile an, der in den von diesemModul
erzeugten Stack-Traces angezeigt wird. Standard:0
.initializeImportMeta
<Function> Wird während der Auswertung diesesModuls
aufgerufen, um dasimport.meta
zu initialisieren.meta
<import.meta>module
<vm.SourceTextModule>importModuleDynamically
<Function> Wird verwendet, um festzulegen, wie die Module während der Auswertung dieses Moduls geladen werden sollen, wennimport()
aufgerufen wird. Diese Option ist Teil der experimentellen Modul-API. Wir empfehlen, sie nicht in einer Produktionsumgebung zu verwenden. Detaillierte Informationen finden Sie unter Unterstützung von dynamischemimport()
in Kompilierungs-APIs.
Erstellt eine neue SourceTextModule
-Instanz.
Eigenschaften, die dem import.meta
-Objekt zugewiesen werden und Objekte sind, können dem Modul den Zugriff auf Informationen außerhalb des angegebenen Kontextes
ermöglichen. Verwenden Sie vm.runInContext()
, um Objekte in einem bestimmten Kontext zu erstellen.
import vm from 'node:vm'
const contextifiedObject = vm.createContext({ secret: 42 })
const module = new vm.SourceTextModule('Object.getPrototypeOf(import.meta.prop).secret = secret;', {
initializeImportMeta(meta) {
// Hinweis: Dieses Objekt wird im obersten Kontext erstellt. Daher
// verweist Object.getPrototypeOf(import.meta.prop) auf die
// Object.prototype im obersten Kontext und nicht auf die im
// kontextualisierten Objekt.
meta.prop = {}
},
})
// Da das Modul keine Abhängigkeiten hat, wird die Linker-Funktion niemals aufgerufen.
await module.link(() => {})
await module.evaluate()
// Jetzt ist Object.prototype.secret gleich 42.
//
// Um dieses Problem zu beheben, ersetzen Sie
// meta.prop = {};
// oben mit
// meta.prop = vm.runInContext('{}', contextifiedObject);
const vm = require('node:vm')
const contextifiedObject = vm.createContext({ secret: 42 })
;(async () => {
const module = new vm.SourceTextModule('Object.getPrototypeOf(import.meta.prop).secret = secret;', {
initializeImportMeta(meta) {
// Hinweis: Dieses Objekt wird im obersten Kontext erstellt. Daher
// verweist Object.getPrototypeOf(import.meta.prop) auf die
// Object.prototype im obersten Kontext und nicht auf die im
// kontextualisierten Objekt.
meta.prop = {}
},
})
// Da das Modul keine Abhängigkeiten hat, wird die Linker-Funktion niemals aufgerufen.
await module.link(() => {})
await module.evaluate()
// Jetzt ist Object.prototype.secret gleich 42.
//
// Um dieses Problem zu beheben, ersetzen Sie
// meta.prop = {};
// oben mit
// meta.prop = vm.runInContext('{}', contextifiedObject);
})()
sourceTextModule.createCachedData()
Hinzugefügt in: v13.7.0, v12.17.0
- Gibt zurück: <Buffer>
Erstellt einen Code-Cache, der mit der cachedData
-Option des SourceTextModule
-Konstruktors verwendet werden kann. Gibt einen Buffer
zurück. Diese Methode kann beliebig oft aufgerufen werden, bevor das Modul ausgewertet wurde.
Der Code-Cache des SourceTextModule
enthält keine JavaScript-beobachtbaren Zustände. Der Code-Cache kann sicher zusammen mit dem Skriptquelltext gespeichert und zur mehrfachen Erstellung neuer SourceTextModule
-Instanzen verwendet werden.
Funktionen in der SourceTextModule
-Quelle können als verzögert kompilierbar markiert werden und werden nicht bei der Konstruktion des SourceTextModule
kompiliert. Diese Funktionen werden kompiliert, wenn sie das erste Mal aufgerufen werden. Der Code-Cache serialisiert die Metadaten, die V8 derzeit über das SourceTextModule
kennt und die er verwenden kann, um zukünftige Kompilierungen zu beschleunigen.
// Erstelle ein anfängliches Modul
const module = new vm.SourceTextModule('const a = 1;')
// Erstelle zwischengespeicherte Daten aus diesem Modul
const cachedData = module.createCachedData()
// Erstelle ein neues Modul mit den zwischengespeicherten Daten. Der Code muss derselbe sein.
const module2 = new vm.SourceTextModule('const a = 1;', { cachedData })
Klasse: vm.SyntheticModule
Hinzugefügt in: v13.0.0, v12.16.0
[Stabil: 1 - Experimentell]
Stabil: 1 Stabilität: 1 - Experimentell
Diese Funktion ist nur mit dem Befehlsflag --experimental-vm-modules
aktiviert verfügbar.
- Erweitert: <vm.Module>
Die Klasse vm.SyntheticModule
bietet den Synthetic Module Record, wie er in der WebIDL-Spezifikation definiert ist. Der Zweck von synthetischen Modulen besteht darin, eine generische Schnittstelle für die Bereitstellung von Nicht-JavaScript-Quellen für ECMAScript-Modulgraphen bereitzustellen.
const vm = require('node:vm')
const source = '{ "a": 1 }'
const module = new vm.SyntheticModule(['default'], function () {
const obj = JSON.parse(source)
this.setExport('default', obj)
})
// Verwende `module` bei der Verknüpfung...
new vm.SyntheticModule(exportNames, evaluateCallback[, options])
Hinzugefügt in: v13.0.0, v12.16.0
exportNames
<string[]> Array von Namen, die aus dem Modul exportiert werden.evaluateCallback
<Funktion> Wird aufgerufen, wenn das Modul ausgewertet wird.options
identifier
<string> Zeichenkette, die in Stacktraces verwendet wird. Standard:'vm:module(i)'
, wobeii
ein kontextspezifischer aufsteigender Index ist.context
<Object> Das kontextifizierte Objekt, das von dervm.createContext()
-Methode zurückgegeben wird, um diesesModule
zu kompilieren und auszuwerten.
Erstellt eine neue SyntheticModule
-Instanz.
Objekte, die den Exporten dieser Instanz zugewiesen sind, können es Importeuren des Moduls ermöglichen, auf Informationen außerhalb des angegebenen context
zuzugreifen. Verwenden Sie vm.runInContext()
, um Objekte in einem bestimmten Kontext zu erstellen.
syntheticModule.setExport(name, value)
Hinzugefügt in: v13.0.0, v12.16.0
name
<string> Name des zu setzenden Exports.value
<any> Der Wert, auf den der Export gesetzt werden soll.
Diese Methode wird verwendet, nachdem das Modul verknüpft wurde, um die Werte der Exporte zu setzen. Wenn sie aufgerufen wird, bevor das Modul verknüpft wurde, wird ein ERR_VM_MODULE_STATUS
-Fehler ausgelöst.
import vm from 'node:vm'
const m = new vm.SyntheticModule(['x'], () => {
m.setExport('x', 1)
})
await m.link(() => {})
await m.evaluate()
assert.strictEqual(m.namespace.x, 1)
const vm = require('node:vm')
;(async () => {
const m = new vm.SyntheticModule(['x'], () => {
m.setExport('x', 1)
})
await m.link(() => {})
await m.evaluate()
assert.strictEqual(m.namespace.x, 1)
})()
vm.compileFunction(code[, params[, options]])
[Historie]
Version | Änderungen |
---|---|
v21.7.0, v20.12.0 | Unterstützung für vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER hinzugefügt. |
v19.6.0, v18.15.0 | Der Rückgabewert enthält jetzt cachedDataRejected mit der gleichen Semantik wie die vm.Script -Version, wenn die Option cachedData übergeben wurde. |
v17.0.0, v16.12.0 | Unterstützung für Importattribute für den Parameter importModuleDynamically hinzugefügt. |
v15.9.0 | Option importModuleDynamically wieder hinzugefügt. |
v14.3.0 | Entfernung von importModuleDynamically aufgrund von Kompatibilitätsproblemen. |
v14.1.0, v13.14.0 | Die Option importModuleDynamically wird jetzt unterstützt. |
v10.10.0 | Hinzugefügt in: v10.10.0 |
code
<string> Der Körper der zu kompilierenden Funktion.params
<string[]> Ein Array von Strings, das alle Parameter für die Funktion enthält.options
<Object>filename
<string> Gibt den Dateinamen an, der in Stacktraces verwendet wird, die von diesem Skript erzeugt werden. Standard:''
.lineOffset
<number> Gibt den Zeilennummer-Offset an, der in Stacktraces angezeigt wird, die von diesem Skript erzeugt werden. Standard:0
.columnOffset
<number> Gibt den Spaltennummer-Offset der ersten Zeile an, der in Stacktraces angezeigt wird, die von diesem Skript erzeugt werden. Standard:0
.cachedData
<Buffer> | <TypedArray> | <DataView> Stellt einen optionalenBuffer
oderTypedArray
oderDataView
mit den Code-Cache-Daten von V8 für die bereitgestellte Quelle bereit. Dies muss durch einen vorherigen Aufruf vonvm.compileFunction()
mit dem gleichencode
undparams
erzeugt werden.produceCachedData
<boolean> Gibt an, ob neue Cache-Daten erzeugt werden sollen. Standard:false
.parsingContext
<Object> Das kontextualisierte Objekt, in dem die besagte Funktion kompiliert werden soll.contextExtensions
<Object[]> Ein Array, das eine Sammlung von Kontext-Erweiterungen (Objekte, die den aktuellen Gültigkeitsbereich umhüllen) enthält, die während der Kompilierung angewendet werden sollen. Standard:[]
.
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Wird verwendet, um anzugeben, wie die Module während der Auswertung dieser Funktion geladen werden sollen, wennimport()
aufgerufen wird. Diese Option ist Teil der experimentellen Module-API. Wir empfehlen die Verwendung in einer Produktionsumgebung nicht. Detaillierte Informationen finden Sie unter Unterstützung von dynamischemimport()
in Kompilierungs-APIs.- Gibt zurück: <Function>
Kompiliert den gegebenen Code in den bereitgestellten Kontext (wenn kein Kontext bereitgestellt wird, wird der aktuelle Kontext verwendet) und gibt ihn, in eine Funktion mit den gegebenen params
eingeschlossen, zurück.
vm.constants
Hinzugefügt in: v21.7.0, v20.12.0
Gibt ein Objekt zurück, das häufig verwendete Konstanten für VM-Operationen enthält.
vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER
Hinzugefügt in: v21.7.0, v20.12.0
[Stabil: 1 - Experimentell]
Stabil: 1 Stabilität: 1.1 - Aktive Entwicklung
Eine Konstante, die als Option importModuleDynamically
für vm.Script
und vm.compileFunction()
verwendet werden kann, sodass Node.js den Standard-ESM-Loader aus dem Hauptkontext verwendet, um das angeforderte Modul zu laden.
Detaillierte Informationen finden Sie unter Unterstützung von dynamischem import()
in Kompilierungs-APIs.
vm.createContext([contextObject[, options]])
[Verlauf]
Version | Änderungen |
---|---|
v22.8.0, v20.18.0 | Das Argument contextObject akzeptiert jetzt vm.constants.DONT_CONTEXTIFY . |
v21.7.0, v20.12.0 | Unterstützung für vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER hinzugefügt. |
v21.2.0, v20.11.0 | Die Option importModuleDynamically wird jetzt unterstützt. |
v14.6.0 | Die Option microtaskMode wird jetzt unterstützt. |
v10.0.0 | Das erste Argument kann keine Funktion mehr sein. |
v10.0.0 | Die Option codeGeneration wird jetzt unterstützt. |
v0.3.1 | Hinzugefügt in: v0.3.1 |
contextObject
<Object> | <vm.constants.DONT_CONTEXTIFY> | <undefined> Entwedervm.constants.DONT_CONTEXTIFY
oder ein Objekt, das kontextualisiert wird. Wennundefined
, wird ein leeres kontextualisiertes Objekt zur Abwärtskompatibilität erstellt.options
<Object>name
<string> Für Menschen lesbarer Name des neu erstellten Kontexts. Standard:'VM Context i'
, wobeii
ein aufsteigender numerischer Index des erstellten Kontexts ist.origin
<string> Ursprung, der dem neu erstellten Kontext zu Anzeigezwecken entspricht. Der Ursprung sollte wie eine URL formatiert sein, aber nur das Schema, den Host und den Port (falls erforderlich), wie der Wert der Eigenschafturl.origin
einesURL
-Objekts. Insbesondere sollte diese Zeichenfolge den nachgestellten Schrägstrich weglassen, da dieser einen Pfad bezeichnet. Standard:''
.codeGeneration
<Object>strings
<boolean> Wenn auf false gesetzt, lösen alle Aufrufe voneval
oder Funktionskonstruktoren (Function
,GeneratorFunction
usw.) einenEvalError
aus. Standard:true
.wasm
<boolean> Wenn auf false gesetzt, löst jeder Versuch, ein WebAssembly-Modul zu kompilieren, einenWebAssembly.CompileError
aus. Standard:true
.
microtaskMode
<string> Wenn aufafterEvaluate
gesetzt, werden Mikrotasks (Tasks, die überPromise
s undasync function
s geplant werden) unmittelbar nach Ausführung eines Skripts überscript.runInContext()
ausgeführt. Sie sind in diesem Fall in dentimeout
- undbreakOnSigint
-Bereichen enthalten.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Wird verwendet, um anzugeben, wie die Module geladen werden sollen, wennimport()
in diesem Kontext ohne ein Referrer-Skript oder -Modul aufgerufen wird. Diese Option ist Teil der experimentellen Modul-API. Wir empfehlen nicht, sie in einer Produktionsumgebung zu verwenden. Detaillierte Informationen finden Sie unter Unterstützung von dynamischemimport()
in Kompilierungs-APIs.
Gibt zurück: <Object> kontextualisiertes Objekt.
Wenn das angegebene contextObject
ein Objekt ist, bereitet die Methode vm.createContext()
dieses Objekt vor und gibt einen Verweis darauf zurück, damit es in Aufrufen von vm.runInContext()
oder script.runInContext()
verwendet werden kann. Innerhalb solcher Skripte wird das globale Objekt vom contextObject
umschlossen, wobei alle seine vorhandenen Eigenschaften beibehalten werden, aber auch die integrierten Objekte und Funktionen vorhanden sind, die jedes Standard-globale Objekt hat. Außerhalb von Skripten, die vom VM-Modul ausgeführt werden, bleiben globale Variablen unverändert.
const vm = require('node:vm')
global.globalVar = 3
const context = { globalVar: 1 }
vm.createContext(context)
vm.runInContext('globalVar *= 2;', context)
console.log(context)
// Gibt aus: { globalVar: 2 }
console.log(global.globalVar)
// Gibt aus: 3
Wenn contextObject
weggelassen wird (oder explizit als undefined
übergeben wird), wird ein neues, leeres kontextualisiertes Objekt zurückgegeben.
Wenn das globale Objekt im neu erstellten Kontext kontextualisiert wird, weist es einige Eigenheiten im Vergleich zu gewöhnlichen globalen Objekten auf. Beispielsweise kann es nicht eingefroren werden. Um einen Kontext ohne die Eigenheiten der Kontextualisierung zu erstellen, übergeben Sie vm.constants.DONT_CONTEXTIFY
als Argument contextObject
. Weitere Informationen finden Sie in der Dokumentation zu vm.constants.DONT_CONTEXTIFY
.
Die Methode vm.createContext()
ist hauptsächlich nützlich, um einen einzelnen Kontext zu erstellen, der zum Ausführen mehrerer Skripte verwendet werden kann. Wenn beispielsweise ein Webbrowser emuliert wird, kann die Methode verwendet werden, um einen einzelnen Kontext zu erstellen, der das globale Objekt eines Fensters darstellt, und dann alle \<script\>
-Tags gemeinsam in diesem Kontext auszuführen.
Der angegebene name
und origin
des Kontexts werden über die Inspector-API sichtbar gemacht.
vm.isContext(object)
Hinzugefügt in: v0.11.7
Gibt true
zurück, wenn das gegebene object
-Objekt mit vm.createContext()
kontextualisiert wurde oder wenn es sich um das globale Objekt eines Kontexts handelt, der mit vm.constants.DONT_CONTEXTIFY
erstellt wurde.
vm.measureMemory([options])
Hinzugefügt in: v13.10.0
[Stabil: 1 - Experimentell]
Stabil: 1 Stabilität: 1 - Experimentell
Misst den von V8 bekannten und von allen Kontexten, die der aktuellen V8-Isolierung bekannt sind, oder dem Hauptkontext verwendeten Speicher.
options
<Object> Optional.mode
<string> Entweder'summary'
oder'detailed'
. Im Zusammenfassungsmodus wird nur der für den Hauptkontext gemessene Speicher zurückgegeben. Im detaillierten Modus wird der für alle Kontexte gemessene Speicher zurückgegeben, die der aktuellen V8-Isolierung bekannt sind. Standard:'summary'
execution
<string> Entweder'default'
oder'eager'
. Bei der Standardausführung wird die Promise erst aufgelöst, nachdem die nächste geplante Garbage Collection beginnt, was eine Weile dauern kann (oder nie, wenn das Programm vor der nächsten GC beendet wird). Bei der eifrigen Ausführung wird die GC sofort gestartet, um den Speicher zu messen. Standard:'default'
Gibt zurück: <Promise> Wenn der Speicher erfolgreich gemessen wurde, wird die Promise mit einem Objekt aufgelöst, das Informationen über die Speichernutzung enthält. Andernfalls wird sie mit einem
ERR_CONTEXT_NOT_INITIALIZED
-Fehler abgelehnt.
Das Format des Objekts, mit dem die zurückgegebene Promise aufgelöst werden kann, ist spezifisch für die V8-Engine und kann sich von einer Version von V8 zur nächsten ändern.
Das zurückgegebene Ergebnis unterscheidet sich von den Statistiken, die von v8.getHeapSpaceStatistics()
zurückgegeben werden, da vm.measureMemory()
den von jedem V8-spezifischen Kontext in der aktuellen Instanz der V8-Engine erreichbaren Speicher misst, während das Ergebnis von v8.getHeapSpaceStatistics()
den von jedem Heap-Bereich in der aktuellen V8-Instanz belegten Speicher misst.
const vm = require('node:vm')
// Misst den vom Hauptkontext verwendeten Speicher.
vm.measureMemory({ mode: 'summary' })
// Das ist das Gleiche wie vm.measureMemory()
.then(result => {
// Das aktuelle Format ist:
// {
// total: {
// jsMemoryEstimate: 2418479, jsMemoryRange: [ 2418479, 2745799 ]
// }
// }
console.log(result)
})
const context = vm.createContext({ a: 1 })
vm.measureMemory({ mode: 'detailed', execution: 'eager' }).then(result => {
// Referenzieren Sie den Kontext hier, damit er nicht GC'ed wird.
// bis die Messung abgeschlossen ist.
console.log(context.a)
// {
// total: {
// jsMemoryEstimate: 2574732,
// jsMemoryRange: [ 2574732, 2904372 ]
// },
// current: {
// jsMemoryEstimate: 2438996,
// jsMemoryRange: [ 2438996, 2768636 ]
// },
// other: [
// {
// jsMemoryEstimate: 135736,
// jsMemoryRange: [ 135736, 465376 ]
// }
// ]
// }
console.log(result)
})
vm.runInContext(code, contextifiedObject[, options])
[Verlauf]
Version | Änderungen |
---|---|
v21.7.0, v20.12.0 | Unterstützung für vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER hinzugefügt. |
v17.0.0, v16.12.0 | Unterstützung für Importattribute zum importModuleDynamically -Parameter hinzugefügt. |
v6.3.0 | Die Option breakOnSigint wird jetzt unterstützt. |
v0.3.1 | Hinzugefügt in: v0.3.1 |
code
<string> Der JavaScript-Code, der kompiliert und ausgeführt werden soll.contextifiedObject
<Object> Das kontextualisierte Objekt, das alsglobal
verwendet wird, wenn dercode
kompiliert und ausgeführt wird.options
<Object> | <string>filename
<string> Gibt den Dateinamen an, der in Stacktraces verwendet wird, die von diesem Skript erzeugt werden. Standard:'evalmachine.\<anonym\>'
.lineOffset
<number> Gibt den Zeilennummer-Offset an, der in Stacktraces angezeigt wird, die von diesem Skript erzeugt werden. Standard:0
.columnOffset
<number> Gibt den Spaltennummer-Offset der ersten Zeile an, der in Stacktraces angezeigt wird, die von diesem Skript erzeugt werden. Standard:0
.displayErrors
<boolean> Wenntrue
, wird, falls einError
während der Kompilierung descode
auftritt, die Codezeile, die den Fehler verursacht, an den Stacktrace angehängt. Standard:true
.timeout
<integer> Gibt die Anzahl der Millisekunden an, die dercode
ausgeführt werden soll, bevor die Ausführung beendet wird. Wenn die Ausführung beendet wird, wird einError
ausgelöst. Dieser Wert muss eine strikt positive Ganzzahl sein.breakOnSigint
<boolean> Wenntrue
, beendet der Empfang vonSIGINT
(+) die Ausführung und löst einenError
aus. Vorhandene Handler für das Ereignis, die überprocess.on('SIGINT')
angehängt wurden, werden während der Skriptausführung deaktiviert, funktionieren aber danach weiterhin. Standard:false
.cachedData
<Buffer> | <TypedArray> | <DataView> Stellt einen optionalenBuffer
oderTypedArray
oderDataView
mit V8s Code-Cache-Daten für die bereitgestellte Quelle bereit.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Wird verwendet, um anzugeben, wie die Module während der Auswertung dieses Skripts geladen werden sollen, wennimport()
aufgerufen wird. Diese Option ist Teil der experimentellen Module-API. Wir empfehlen nicht, sie in einer Produktionsumgebung zu verwenden. Detaillierte Informationen finden Sie unter Unterstützung von dynamischemimport()
in Kompilierungs-APIs.
Die Methode vm.runInContext()
kompiliert code
, führt ihn im Kontext des contextifiedObject
aus und gibt dann das Ergebnis zurück. Der ausgeführte Code hat keinen Zugriff auf den lokalen Gültigkeitsbereich. Das contextifiedObject
-Objekt muss zuvor mit der Methode vm.createContext()
kontextualisiert worden sein.
Wenn options
ein String ist, dann gibt er den Dateinamen an.
Das folgende Beispiel kompiliert und führt verschiedene Skripte mit einem einzigen kontextualisierten Objekt aus:
const vm = require('node:vm')
const contextObject = { globalVar: 1 }
vm.createContext(contextObject)
for (let i = 0; i < 10; ++i) {
vm.runInContext('globalVar *= 2;', contextObject)
}
console.log(contextObject)
// Gibt aus: { globalVar: 1024 }
vm.runInNewContext(code[, contextObject[, options]])
[Verlauf]
Version | Änderungen |
---|---|
v22.8.0, v20.18.0 | Das Argument contextObject akzeptiert nun vm.constants.DONT_CONTEXTIFY . |
v21.7.0, v20.12.0 | Unterstützung für vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER hinzugefügt. |
v17.0.0, v16.12.0 | Unterstützung für Importattribute für den Parameter importModuleDynamically hinzugefügt. |
v14.6.0 | Die Option microtaskMode wird jetzt unterstützt. |
v10.0.0 | Die Option contextCodeGeneration wird jetzt unterstützt. |
v6.3.0 | Die Option breakOnSigint wird jetzt unterstützt. |
v0.3.1 | Hinzugefügt in: v0.3.1 |
code
<string> Der JavaScript-Code, der kompiliert und ausgeführt werden soll.contextObject
<Object> | <vm.constants.DONT_CONTEXTIFY> | <undefined> Entwedervm.constants.DONT_CONTEXTIFY
oder ein Objekt, das kontextifiziert wird. Wennundefined
, wird ein leeres kontextifiziertes Objekt zur Abwärtskompatibilität erstellt.filename
<string> Gibt den Dateinamen an, der in Stacktraces verwendet wird, die von diesem Skript erzeugt werden. Standard:'evalmachine.\<anonymous\>'
.lineOffset
<number> Gibt den Zeilennummernoffset an, der in Stacktraces angezeigt wird, die von diesem Skript erzeugt werden. Standard:0
.columnOffset
<number> Gibt den Spaltennummernoffset der ersten Zeile an, der in Stacktraces angezeigt wird, die von diesem Skript erzeugt werden. Standard:0
.displayErrors
<boolean> Wenntrue
, wird die Codezeile, die den Fehler verursacht hat, an den Stacktrace angehängt, wenn während der Kompilierung descode
einError
auftritt. Standard:true
.timeout
<integer> Gibt die Anzahl der Millisekunden an, diecode
ausgeführt werden soll, bevor die Ausführung beendet wird. Wenn die Ausführung beendet wird, wird einError
ausgelöst. Dieser Wert muss eine streng positive ganze Zahl sein.breakOnSigint
<boolean> Wenntrue
, beendet der Empfang vonSIGINT
(+) die Ausführung und löst einenError
aus. Vorhandene Handler für das Ereignis, die überprocess.on('SIGINT')
angehängt wurden, werden während der Skriptausführung deaktiviert, funktionieren aber danach weiterhin. Standard:false
.contextName
<string> Für Menschen lesbarer Name des neu erstellten Kontexts. Standard:'VM Context i'
, wobeii
ein aufsteigender numerischer Index des erstellten Kontexts ist.contextOrigin
<string> Ursprung, der dem neu erstellten Kontext zu Anzeigezwecken entspricht. Der Ursprung sollte wie eine URL formatiert sein, aber nur mit dem Schema, dem Host und dem Port (falls erforderlich), wie der Wert der Eigenschafturl.origin
einesURL
-Objekts. Insbesondere sollte diese Zeichenfolge den nachgestellten Schrägstrich weglassen, da dieser einen Pfad kennzeichnet. Standard:''
.contextCodeGeneration
<Object>strings
<boolean> Wenn auf false gesetzt, lösen alle Aufrufe voneval
oder Funktionskonstruktoren (Function
,GeneratorFunction
usw.) einenEvalError
aus. Standard:true
.wasm
<boolean> Wenn auf false gesetzt, löst jeder Versuch, ein WebAssembly-Modul zu kompilieren, einenWebAssembly.CompileError
aus. Standard:true
.cachedData
<Buffer> | <TypedArray> | <DataView> Stellt einen optionalenBuffer
oderTypedArray
oderDataView
mit den Code-Cache-Daten von V8 für die bereitgestellte Quelle bereit.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Wird verwendet, um anzugeben, wie die Module während der Auswertung dieses Skripts geladen werden sollen, wennimport()
aufgerufen wird. Diese Option ist Teil der experimentellen Module-API. Wir empfehlen nicht, sie in einer Produktionsumgebung zu verwenden. Ausführliche Informationen finden Sie unter Unterstützung von dynamischemimport()
in Kompilierungs-APIs.microtaskMode
<string> Wenn aufafterEvaluate
gesetzt, werden Mikrotasks (Aufgaben, die durchPromise
s undasync function
s geplant werden) unmittelbar nach dem Ausführen des Skripts ausgeführt. Sie sind in diesem Fall in dentimeout
- undbreakOnSigint
-Bereichen enthalten.
Gibt zurück: <any> Das Ergebnis der letzten im Skript ausgeführten Anweisung.
Diese Methode ist eine Abkürzung für (new vm.Script(code, options)).runInContext(vm.createContext(options), options)
. Wenn options
eine Zeichenfolge ist, gibt sie den Dateinamen an.
Sie erledigt mehrere Dinge gleichzeitig:
Das folgende Beispiel kompiliert und führt Code aus, der eine globale Variable inkrementiert und eine neue festlegt. Diese globalen Variablen sind im contextObject
enthalten.
const vm = require('node:vm')
const contextObject = {
animal: 'cat',
count: 2,
}
vm.runInNewContext('count += 1; name = "kitty"', contextObject)
console.log(contextObject)
// Gibt aus: { animal: 'cat', count: 3, name: 'kitty' }
// Dies würde einen Fehler auslösen, wenn der Kontext aus einem kontextifizierten Objekt erstellt würde.
// vm.constants.DONT_CONTEXTIFY ermöglicht das Erstellen von Kontexten mit gewöhnlichen globalen Objekten, die
// eingefroren werden können.
const frozenContext = vm.runInNewContext('Object.freeze(globalThis); globalThis;', vm.constants.DONT_CONTEXTIFY)
vm.runInThisContext(code[, options])
[Verlauf]
Version | Änderungen |
---|---|
v21.7.0, v20.12.0 | Unterstützung für vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER hinzugefügt. |
v17.0.0, v16.12.0 | Unterstützung für Importattribute zum Parameter importModuleDynamically hinzugefügt. |
v6.3.0 | Die Option breakOnSigint wird jetzt unterstützt. |
v0.3.1 | Hinzugefügt in: v0.3.1 |
code
<string> Der zu kompilierende und auszuführende JavaScript-Code.filename
<string> Gibt den Dateinamen an, der in Stacktraces verwendet wird, die von diesem Skript erzeugt werden. Standard:'evalmachine.\<anonymous\>'
.lineOffset
<number> Gibt den Zeilennummernoffset an, der in Stacktraces angezeigt wird, die von diesem Skript erzeugt werden. Standard:0
.columnOffset
<number> Gibt den Spaltennummernoffset der ersten Zeile an, der in Stacktraces angezeigt wird, die von diesem Skript erzeugt werden. Standard:0
.displayErrors
<boolean> Wenntrue
, wird bei Auftreten einesError
beim Kompilieren descode
die Codezeile, die den Fehler verursacht, an den Stacktrace angehängt. Standard:true
.timeout
<integer> Gibt die Anzahl der Millisekunden an, die dercode
ausgeführt werden soll, bevor die Ausführung beendet wird. Wenn die Ausführung beendet wird, wird einError
ausgelöst. Dieser Wert muss eine strikt positive Ganzzahl sein.breakOnSigint
<boolean> Wenntrue
, wird beim Empfangen vonSIGINT
(+) die Ausführung beendet und einError
ausgelöst. Vorhandene Handler für das Ereignis, die überprocess.on('SIGINT')
angehängt wurden, werden während der Skriptausführung deaktiviert, funktionieren aber danach weiter. Standard:false
.cachedData
<Buffer> | <TypedArray> | <DataView> Stellt einen optionalenBuffer
oderTypedArray
oderDataView
mit den Code-Cache-Daten von V8 für die bereitgestellte Quelle bereit.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Wird verwendet, um anzugeben, wie die Module während der Auswertung dieses Skripts geladen werden sollen, wennimport()
aufgerufen wird. Diese Option ist Teil der experimentellen Module-API. Wir empfehlen, sie nicht in einer Produktionsumgebung zu verwenden. Detaillierte Informationen finden Sie unter Unterstützung von dynamischemimport()
in Kompilierungs-APIs.
Gibt zurück: <any> das Ergebnis der letzten im Skript ausgeführten Anweisung.
vm.runInThisContext()
kompiliert code
, führt es im Kontext des aktuellen global
aus und gibt das Ergebnis zurück. Ausgeführter Code hat keinen Zugriff auf den lokalen Gültigkeitsbereich, aber Zugriff auf das aktuelle global
-Objekt.
Wenn options
ein String ist, gibt er den Dateinamen an.
Das folgende Beispiel veranschaulicht die Verwendung von vm.runInThisContext()
und der JavaScript-Funktion eval()
zum Ausführen desselben Codes:
const vm = require('node:vm')
let localVar = 'initial value'
const vmResult = vm.runInThisContext('localVar = "vm";')
console.log(`vmResult: '${vmResult}', localVar: '${localVar}'`)
// Gibt aus: vmResult: 'vm', localVar: 'initial value'
const evalResult = eval('localVar = "eval";')
console.log(`evalResult: '${evalResult}', localVar: '${localVar}'`)
// Gibt aus: evalResult: 'eval', localVar: 'eval'
Da vm.runInThisContext()
keinen Zugriff auf den lokalen Gültigkeitsbereich hat, bleibt localVar
unverändert. Im Gegensatz dazu hat eval()
Zugriff auf den lokalen Gültigkeitsbereich, sodass der Wert von localVar
geändert wird. In dieser Hinsicht ähnelt vm.runInThisContext()
einem indirekten eval()
-Aufruf, z. B. (0,eval)('code')
.
Beispiel: Ausführen eines HTTP-Servers in einer VM
Wenn entweder script.runInThisContext()
oder vm.runInThisContext()
verwendet wird, wird der Code im aktuellen globalen V8-Kontext ausgeführt. Der an diesen VM-Kontext übergebene Code hat einen eigenen isolierten Geltungsbereich.
Um einen einfachen Webserver mithilfe des node:http
-Moduls auszuführen, muss der an den Kontext übergebene Code entweder selbst require('node:http')
aufrufen oder eine Referenz zum node:http
-Modul an ihn übergeben bekommen. Zum Beispiel:
'use strict'
const vm = require('node:vm')
const code = `
((require) => {
const http = require('node:http');
http.createServer((request, response) => {
response.writeHead(200, { 'Content-Type': 'text/plain' });
response.end('Hallo Welt\\n');
}).listen(8124);
console.log('Server läuft unter http://127.0.0.1:8124/');
})`
vm.runInThisContext(code)(require)
Das require()
im obigen Fall teilt sich den Zustand mit dem Kontext, aus dem es übergeben wird. Dies kann Risiken mit sich bringen, wenn nicht vertrauenswürdiger Code ausgeführt wird, z. B. das ungewollte Ändern von Objekten im Kontext.
Was bedeutet es, ein Objekt zu "kontextualisieren"?
Jedes in Node.js ausgeführte JavaScript wird im Geltungsbereich eines "Kontexts" ausgeführt. Laut V8 Embedder's Guide:
Wenn die Methode vm.createContext()
mit einem Objekt aufgerufen wird, wird das Argument contextObject
verwendet, um das globale Objekt einer neuen Instanz eines V8-Kontexts zu umschließen (wenn contextObject
undefined
ist, wird ein neues Objekt aus dem aktuellen Kontext erstellt, bevor es kontextualisiert wird). Dieser V8-Kontext bietet dem mit den Methoden des node:vm
-Moduls ausgeführten code
eine isolierte globale Umgebung, in der er arbeiten kann. Der Prozess der Erstellung des V8-Kontexts und dessen Verknüpfung mit dem contextObject
im äußeren Kontext wird in diesem Dokument als "Kontextualisierung" des Objekts bezeichnet.
Die Kontextualisierung würde einige Eigenheiten für den globalThis
-Wert im Kontext einführen. Zum Beispiel kann er nicht eingefroren werden, und er ist nicht referenziell gleich dem contextObject
im äußeren Kontext.
const vm = require('node:vm')
// Eine undefinierte `contextObject`-Option bewirkt, dass das globale Objekt kontextualisiert wird.
const context = vm.createContext()
console.log(vm.runInContext('globalThis', context) === context) // false
// Ein kontextualisiertes globales Objekt kann nicht eingefroren werden.
try {
vm.runInContext('Object.freeze(globalThis);', context)
} catch (e) {
console.log(e) // TypeError: Kann nicht einfrieren
}
console.log(vm.runInContext('globalThis.foo = 1; foo;', context)) // 1
Um einen Kontext mit einem normalen globalen Objekt zu erstellen und über weniger Eigenheiten auf einen globalen Proxy im äußeren Kontext zuzugreifen, geben Sie vm.constants.DONT_CONTEXTIFY
als contextObject
-Argument an.
vm.constants.DONT_CONTEXTIFY
Diese Konstante, wenn sie als contextObject
-Argument in VM-APIs verwendet wird, weist Node.js an, einen Kontext zu erstellen, ohne sein globales Objekt auf eine Node.js-spezifische Weise mit einem anderen Objekt zu umhüllen. Infolgedessen würde sich der globalThis
-Wert innerhalb des neuen Kontexts eher wie ein gewöhnlicher verhalten.
const vm = require('node:vm')
// Verwenden Sie vm.constants.DONT_CONTEXTIFY, um das globale Objekt einzufrieren.
const context = vm.createContext(vm.constants.DONT_CONTEXTIFY)
vm.runInContext('Object.freeze(globalThis);', context)
try {
vm.runInContext('bar = 1; bar;', context)
} catch (e) {
console.log(e) // Uncaught ReferenceError: bar is not defined
}
Wenn vm.constants.DONT_CONTEXTIFY
als contextObject
-Argument für vm.createContext()
verwendet wird, ist das zurückgegebene Objekt ein Proxy-ähnliches Objekt für das globale Objekt im neu erstellten Kontext mit weniger Node.js-spezifischen Eigenheiten. Es ist referenzgleich mit dem globalThis
-Wert im neuen Kontext, kann von außerhalb des Kontexts modifiziert werden und kann verwendet werden, um direkt auf Built-Ins im neuen Kontext zuzugreifen.
const vm = require('node:vm')
const context = vm.createContext(vm.constants.DONT_CONTEXTIFY)
// Das zurückgegebene Objekt ist referenzgleich mit globalThis im neuen Kontext.
console.log(vm.runInContext('globalThis', context) === context) // true
// Kann verwendet werden, um direkt auf Globale im neuen Kontext zuzugreifen.
console.log(context.Array) // [Function: Array]
vm.runInContext('foo = 1;', context)
console.log(context.foo) // 1
context.bar = 1
console.log(vm.runInContext('bar;', context)) // 1
// Kann eingefroren werden und es wirkt sich auf den inneren Kontext aus.
Object.freeze(context)
try {
vm.runInContext('baz = 1; baz;', context)
} catch (e) {
console.log(e) // Uncaught ReferenceError: baz is not defined
}
Timeout-Interaktionen mit asynchronen Tasks und Promises
Promise
s und async function
s können Tasks planen, die von der JavaScript-Engine asynchron ausgeführt werden. Standardmäßig werden diese Tasks ausgeführt, nachdem alle JavaScript-Funktionen auf dem aktuellen Stack die Ausführung beendet haben. Dies ermöglicht das Umgehen der Funktionalität der timeout
- und breakOnSigint
-Optionen.
Beispielsweise plant der folgende Code, der von vm.runInNewContext()
mit einem Timeout von 5 Millisekunden ausgeführt wird, eine Endlosschleife, die nach dem Auflösen eines Promises ausgeführt werden soll. Die geplante Schleife wird vom Timeout nie unterbrochen:
const vm = require('node:vm')
function loop() {
console.log('entering loop')
while (1) console.log(Date.now())
}
vm.runInNewContext('Promise.resolve().then(() => loop());', { loop, console }, { timeout: 5 })
// Dies wird *vor* 'entering loop' (!) ausgegeben.
console.log('done executing')
Dies kann behoben werden, indem microtaskMode: 'afterEvaluate'
an den Code übergeben wird, der den Context
erstellt:
const vm = require('node:vm')
function loop() {
while (1) console.log(Date.now())
}
vm.runInNewContext(
'Promise.resolve().then(() => loop());',
{ loop, console },
{ timeout: 5, microtaskMode: 'afterEvaluate' }
)
In diesem Fall wird die über promise.then()
geplante Microtask ausgeführt, bevor von vm.runInNewContext()
zurückgekehrt wird, und wird von der timeout
-Funktionalität unterbrochen. Dies gilt nur für Code, der in einem vm.Context
ausgeführt wird, sodass z.B. vm.runInThisContext()
diese Option nicht berücksichtigt.
Promise-Callbacks werden in die Microtask-Queue des Kontexts eingetragen, in dem sie erstellt wurden. Wenn beispielsweise () => loop()
im obigen Beispiel nur durch loop
ersetzt wird, wird loop
in die globale Microtask-Queue gepusht, da es sich um eine Funktion aus dem äußeren (Haupt-)Kontext handelt und somit auch dem Timeout entkommen kann.
Wenn asynchrone Planungsfunktionen wie process.nextTick()
, queueMicrotask()
, setTimeout()
, setImmediate()
usw. innerhalb eines vm.Context
verfügbar gemacht werden, werden ihnen übergebene Funktionen zu globalen Queues hinzugefügt, die von allen Kontexten gemeinsam genutzt werden. Daher sind über diese Funktionen übergebene Callbacks auch nicht über den Timeout steuerbar.
Unterstützung von dynamischem import()
in Kompilierungs-APIs
Die folgenden APIs unterstützen eine importModuleDynamically
-Option, um dynamisches import()
in Code zu aktivieren, der vom vm-Modul kompiliert wird.
new vm.Script
vm.compileFunction()
new vm.SourceTextModule
vm.runInThisContext()
vm.runInContext()
vm.runInNewContext()
vm.createContext()
Diese Option ist immer noch Teil der experimentellen Module-API. Wir empfehlen, sie nicht in einer Produktionsumgebung zu verwenden.
Wenn die importModuleDynamically
-Option nicht angegeben oder undefiniert ist
Wenn diese Option nicht angegeben ist oder undefined
ist, kann Code, der import()
enthält, weiterhin von den vm-APIs kompiliert werden. Wenn der kompilierte Code jedoch ausgeführt wird und tatsächlich import()
aufruft, wird das Ergebnis mit ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING
abgelehnt.
Wenn importModuleDynamically
vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER
ist
Diese Option wird derzeit für vm.SourceTextModule
nicht unterstützt.
Mit dieser Option würde Node.js, wenn ein import()
im kompilierten Code initiiert wird, den standardmäßigen ESM-Loader aus dem Hauptkontext verwenden, um das angeforderte Modul zu laden und es an den ausgeführten Code zurückzugeben.
Dies ermöglicht dem kompilierten Code den Zugriff auf integrierte Node.js-Module wie fs
oder http
. Wenn der Code in einem anderen Kontext ausgeführt wird, beachten Sie, dass die von Modulen erstellten Objekte, die aus dem Hauptkontext geladen wurden, immer noch aus dem Hauptkontext stammen und nicht instanceof
integrierten Klassen im neuen Kontext sind.
const { Script, constants } = require('node:vm')
const script = new Script('import("node:fs").then(({readFile}) => readFile instanceof Function)', {
importModuleDynamically: constants.USE_MAIN_CONTEXT_DEFAULT_LOADER,
})
// false: URL, die aus dem Hauptkontext geladen wurde, ist keine Instanz der Funktionsklasse
// im neuen Kontext.
script.runInNewContext().then(console.log)
import { Script, constants } from 'node:vm'
const script = new Script('import("node:fs").then(({readFile}) => readFile instanceof Function)', {
importModuleDynamically: constants.USE_MAIN_CONTEXT_DEFAULT_LOADER,
})
// false: URL, die aus dem Hauptkontext geladen wurde, ist keine Instanz der Funktionsklasse
// im neuen Kontext.
script.runInNewContext().then(console.log)
Diese Option ermöglicht dem Skript oder der Funktion auch das Laden von Benutzermodulen:
import { Script, constants } from 'node:vm'
import { resolve } from 'node:path'
import { writeFileSync } from 'node:fs'
// Schreibe test.js und test.txt in das Verzeichnis, in dem sich das aktuelle Skript
// befindet.
writeFileSync(resolve(import.meta.dirname, 'test.mjs'), 'export const filename = "./test.json";')
writeFileSync(resolve(import.meta.dirname, 'test.json'), '{"hello": "world"}')
// Kompilieren Sie ein Skript, das test.mjs und dann test.json lädt
// so, als ob sich das Skript im selben Verzeichnis befindet.
const script = new Script(
`(async function() {
const { filename } = await import('./test.mjs');
return import(filename, { with: { type: 'json' } })
})();`,
{
filename: resolve(import.meta.dirname, 'test-with-default.js'),
importModuleDynamically: constants.USE_MAIN_CONTEXT_DEFAULT_LOADER,
}
)
// { default: { hello: 'world' } }
script.runInThisContext().then(console.log)
const { Script, constants } = require('node:vm')
const { resolve } = require('node:path')
const { writeFileSync } = require('node:fs')
// Schreibe test.js und test.txt in das Verzeichnis, in dem sich das aktuelle Skript
// befindet.
writeFileSync(resolve(__dirname, 'test.mjs'), 'export const filename = "./test.json";')
writeFileSync(resolve(__dirname, 'test.json'), '{"hello": "world"}')
// Kompilieren Sie ein Skript, das test.mjs und dann test.json lädt
// so, als ob sich das Skript im selben Verzeichnis befindet.
const script = new Script(
`(async function() {
const { filename } = await import('./test.mjs');
return import(filename, { with: { type: 'json' } })
})();`,
{
filename: resolve(__dirname, 'test-with-default.js'),
importModuleDynamically: constants.USE_MAIN_CONTEXT_DEFAULT_LOADER,
}
)
// { default: { hello: 'world' } }
script.runInThisContext().then(console.log)
Es gibt einige Einschränkungen beim Laden von Benutzermodulen mit dem Standard-Loader aus dem Hauptkontext:
Wenn importModuleDynamically
eine Funktion ist
Wenn importModuleDynamically
eine Funktion ist, wird sie aufgerufen, wenn import()
im kompilierten Code aufgerufen wird, damit Benutzer anpassen können, wie das angeforderte Modul kompiliert und ausgewertet werden soll. Derzeit muss die Node.js-Instanz mit dem Flag --experimental-vm-modules
gestartet werden, damit diese Option funktioniert. Wenn das Flag nicht gesetzt ist, wird dieser Callback ignoriert. Wenn der ausgewertete Code tatsächlich import()
aufruft, wird das Ergebnis mit ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAG
abgelehnt.
Der Callback importModuleDynamically(specifier, referrer, importAttributes)
hat die folgende Signatur:
specifier
<string> Bezeichner, der animport()
übergeben wird.referrer
<vm.Script> | <Function> | <vm.SourceTextModule> | <Object> Der Referrer ist das kompiliertevm.Script
fürnew vm.Script
,vm.runInThisContext
,vm.runInContext
undvm.runInNewContext
. Es ist die kompilierteFunction
fürvm.compileFunction
, das kompiliertevm.SourceTextModule
fürnew vm.SourceTextModule
und das KontextObject
fürvm.createContext()
.importAttributes
<Object> Der"with"
-Wert, der an den optionalen ParameteroptionsExpression
übergeben wird, oder ein leeres Objekt, wenn kein Wert angegeben wurde.- Gibt zurück: <Module Namespace Object> | <vm.Module> Die Rückgabe eines
vm.Module
wird empfohlen, um die Fehlernachverfolgung zu nutzen und Probleme mit Namespaces zu vermeiden, diethen
-Funktionsexporte enthalten.
// Dieses Skript muss mit --experimental-vm-modules ausgeführt werden.
import { Script, SyntheticModule } from 'node:vm'
const script = new Script('import("foo.json", { with: { type: "json" } })', {
async importModuleDynamically(specifier, referrer, importAttributes) {
console.log(specifier) // 'foo.json'
console.log(referrer) // Das kompilierte Skript
console.log(importAttributes) // { type: 'json' }
const m = new SyntheticModule(['bar'], () => {})
await m.link(() => {})
m.setExport('bar', { hello: 'world' })
return m
},
})
const result = await script.runInThisContext()
console.log(result) // { bar: { hello: 'world' } }
// Dieses Skript muss mit --experimental-vm-modules ausgeführt werden.
const { Script, SyntheticModule } = require('node:vm')
;(async function main() {
const script = new Script('import("foo.json", { with: { type: "json" } })', {
async importModuleDynamically(specifier, referrer, importAttributes) {
console.log(specifier) // 'foo.json'
console.log(referrer) // Das kompilierte Skript
console.log(importAttributes) // { type: 'json' }
const m = new SyntheticModule(['bar'], () => {})
await m.link(() => {})
m.setExport('bar', { hello: 'world' })
return m
},
})
const result = await script.runInThisContext()
console.log(result) // { bar: { hello: 'world' } }
})()