VM (esecuzione di JavaScript)
[Stabile: 2 - Stabile]
Stabile: 2 Stabilità: 2 - Stabile
Codice sorgente: lib/vm.js
Il modulo node:vm
consente di compilare ed eseguire codice all'interno di contesti della Virtual Machine V8.
Il modulo node:vm
non è un meccanismo di sicurezza. Non utilizzarlo per eseguire codice non attendibile.
Il codice JavaScript può essere compilato ed eseguito immediatamente, oppure compilato, salvato ed eseguito in seguito.
Un caso d'uso comune è eseguire il codice in un contesto V8 diverso. Ciò significa che il codice invocato ha un oggetto globale diverso dal codice chiamante.
Si può fornire il contesto contestualizzando un oggetto. Il codice invocato tratta qualsiasi proprietà nel contesto come una variabile globale. Qualsiasi modifica alle variabili globali causata dal codice invocato si riflette nell'oggetto contesto.
const vm = require('node:vm');
const x = 1;
const context = { x: 2 };
vm.createContext(context); // Contestualizza l'oggetto.
const code = 'x += 40; var y = 17;';
// `x` e `y` sono variabili globali nel contesto.
// Inizialmente, x ha il valore 2 perché quello è il valore di context.x.
vm.runInContext(code, context);
console.log(context.x); // 42
console.log(context.y); // 17
console.log(x); // 1; y non è definito.
Classe: vm.Script
Aggiunto in: v0.3.1
Le istanze della classe vm.Script
contengono script precompilati che possono essere eseguiti in contesti specifici.
new vm.Script(code[, options])
[Cronologia]
Versione | Modifiche |
---|---|
v21.7.0, v20.12.0 | Aggiunto il supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Aggiunto il supporto per gli attributi di importazione al parametro importModuleDynamically . |
v10.6.0 | produceCachedData è deprecato a favore di script.createCachedData() . |
v5.7.0 | Le opzioni cachedData e produceCachedData sono ora supportate. |
v0.3.1 | Aggiunto in: v0.3.1 |
code
<stringa> Il codice JavaScript da compilare.options
<Oggetto> | <stringa>filename
<stringa> Specifica il nome del file utilizzato nelle stack trace prodotte da questo script. Predefinito:'evalmachine.\<anonymous\>'
.lineOffset
<numero> Specifica l'offset del numero di riga visualizzato nelle stack trace prodotte da questo script. Predefinito:0
.columnOffset
<numero> Specifica l'offset del numero di colonna della prima riga visualizzato nelle stack trace prodotte da questo script. Predefinito:0
.cachedData
<Buffer> | <TypedArray> | <DataView> Fornisce unBuffer
oTypedArray
, oDataView
opzionale con i dati della cache del codice di V8 per l'origine fornita. Quando fornito, il valorecachedDataRejected
sarà impostato sutrue
ofalse
a seconda dell'accettazione dei dati da parte di V8.produceCachedData
<booleano> Quandotrue
e nessuncachedData
è presente, V8 tenterà di produrre dati della cache del codice percode
. In caso di successo, verrà prodotto unBuffer
con i dati della cache del codice di V8 e memorizzato nella proprietàcachedData
dell'istanzavm.Script
restituita. Il valorecachedDataProduced
verrà impostato sutrue
ofalse
a seconda che i dati della cache del codice vengano prodotti con successo. Questa opzione è deprecata a favore discript.createCachedData()
. Predefinito:false
.importModuleDynamically
<Funzione> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Utilizzato per specificare come i moduli devono essere caricati durante la valutazione di questo script quando viene chiamatoimport()
. Questa opzione fa parte dell'API dei moduli sperimentali. Si sconsiglia di utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto dell'importazione dinamicaimport()
nelle API di compilazione.
Se options
è una stringa, allora specifica il nome del file.
La creazione di un nuovo oggetto vm.Script
compila code
ma non lo esegue. Il vm.Script
compilato può essere eseguito successivamente più volte. Il code
non è vincolato a nessun oggetto globale; piuttosto, è vincolato prima di ogni esecuzione, solo per quella esecuzione.
script.cachedDataRejected
Aggiunto in: v5.7.0
Quando cachedData
viene fornito per creare vm.Script
, questo valore verrà impostato su true
o false
a seconda dell'accettazione dei dati da parte di V8. Altrimenti il valore è undefined
.
script.createCachedData()
Aggiunto in: v10.6.0
- Restituisce: <Buffer>
Crea una cache di codice che può essere utilizzata con l'opzione cachedData
del costruttore Script
. Restituisce un Buffer
. Questo metodo può essere chiamato in qualsiasi momento e un numero qualsiasi di volte.
La cache di codice di Script
non contiene alcuno stato osservabile di JavaScript. La cache di codice è sicura da salvare insieme al codice sorgente dello script e utilizzata per costruire più istanze Script
.
Le funzioni nel sorgente Script
possono essere contrassegnate come compilate pigramente e non vengono compilate durante la costruzione di Script
. Queste funzioni verranno compilate quando vengono invocate per la prima volta. La cache di codice serializza i metadati che V8 conosce attualmente sullo Script
che può utilizzare per accelerare le compilazioni future.
const script = new vm.Script(`
function add(a, b) {
return a + b;
}
const x = add(1, 2);
`);
const cacheWithoutAdd = script.createCachedData();
// In `cacheWithoutAdd` la funzione `add()` è contrassegnata per la compilazione completa
// al momento dell'invocazione.
script.runInThisContext();
const cacheWithAdd = script.createCachedData();
// `cacheWithAdd` contiene la funzione `add()` completamente compilata.
script.runInContext(contextifiedObject[, options])
[Cronologia]
Versione | Modifiche |
---|---|
v6.3.0 | L'opzione breakOnSigint è ora supportata. |
v0.3.1 | Aggiunto in: v0.3.1 |
contextifiedObject
<Object> Un oggetto contestualizzato come restituito dal metodovm.createContext()
.options
<Object>displayErrors
<boolean> Quandotrue
, se si verifica unError
durante la compilazione delcode
, la riga di codice che causa l'errore viene allegata alla traccia dello stack. Predefinito:true
.timeout
<integer> Specifica il numero di millisecondi per eseguire ilcode
prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà lanciato unError
. Questo valore deve essere un numero intero strettamente positivo.breakOnSigint
<boolean> Setrue
, la ricezione diSIGINT
(+) terminerà l'esecuzione e lancerà unError
. I gestori esistenti per l'evento che sono stati collegati tramiteprocess.on('SIGINT')
sono disabilitati durante l'esecuzione dello script, ma continuano a funzionare dopo. Predefinito:false
.
Restituisce: <any> il risultato dell'ultima istruzione eseguita nello script.
Esegue il codice compilato contenuto dall'oggetto vm.Script
all'interno del contextifiedObject
specificato e restituisce il risultato. L'esecuzione del codice non ha accesso allo scope locale.
L'esempio seguente compila il codice che incrementa una variabile globale, imposta il valore di un'altra variabile globale, quindi esegue il codice più volte. Le variabili globali sono contenute nell'oggetto context
.
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);
// Prints: { animal: 'cat', count: 12, name: 'kitty' }
L'utilizzo delle opzioni timeout
o breakOnSigint
comporterà l'avvio di nuovi cicli di eventi e thread corrispondenti, che hanno un overhead di prestazioni diverso da zero.
script.runInNewContext([contextObject[, options]])
[Cronologia]
Versione | Modifiche |
---|---|
v22.8.0, v20.18.0 | L'argomento contextObject ora accetta vm.constants.DONT_CONTEXTIFY . |
v14.6.0 | L'opzione microtaskMode è ora supportata. |
v10.0.0 | L'opzione contextCodeGeneration è ora supportata. |
v6.3.0 | L'opzione breakOnSigint è ora supportata. |
v0.3.1 | Aggiunto in: v0.3.1 |
contextObject
<Object> | <vm.constants.DONT_CONTEXTIFY> | <undefined> Ovm.constants.DONT_CONTEXTIFY
o un oggetto che verrà contestualizzato. Seundefined
, verrà creato un oggetto contestualizzato vuoto per compatibilità con le versioni precedenti.options
<Object>displayErrors
<boolean> Quandotrue
, se si verifica unError
durante la compilazione delcode
, la riga di codice che causa l'errore viene allegata alla traccia dello stack. Predefinito:true
.timeout
<integer> Specifica il numero di millisecondi per eseguirecode
prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà generato unError
. Questo valore deve essere un numero intero strettamente positivo.breakOnSigint
<boolean> Setrue
, la ricezione diSIGINT
(+) terminerà l'esecuzione e genererà unError
. I gestori esistenti per l'evento che sono stati allegati tramiteprocess.on('SIGINT')
sono disabilitati durante l'esecuzione dello script, ma continuano a funzionare dopo. Predefinito:false
.contextName
<string> Nome leggibile dal umano del contesto appena creato. Predefinito:'VM Context i'
, dovei
è un indice numerico crescente del contesto creato.contextOrigin
<string> Origine corrispondente al contesto appena creato a scopo di visualizzazione. L'origine deve essere formattata come un URL, ma solo con lo schema, l'host e la porta (se necessario), come il valore della proprietàurl.origin
di un oggettoURL
. In particolare, questa stringa dovrebbe omettere la barra finale, poiché denota un percorso. Predefinito:''
.contextCodeGeneration
<Object>strings
<boolean> Se impostato su false, qualsiasi chiamata aeval
o costruttori di funzioni (Function
,GeneratorFunction
, ecc.) genererà unEvalError
. Predefinito:true
.wasm
<boolean> Se impostato su false, qualsiasi tentativo di compilare un modulo WebAssembly genererà unWebAssembly.CompileError
. Predefinito:true
.microtaskMode
<string> Se impostato suafterEvaluate
, i microtask (task pianificati tramitePromise
easync function
) verranno eseguiti immediatamente dopo l'esecuzione dello script. In questo caso, sono inclusi negli ambititimeout
ebreakOnSigint
.
Restituisce: <any> il risultato dell'ultima istruzione eseguita nello script.
Questo metodo è una scorciatoia per script.runInContext(vm.createContext(options), options)
. Esegue diverse operazioni contemporaneamente:
L'esempio seguente compila il codice che imposta una variabile globale, quindi esegue il codice più volte in contesti diversi. Le variabili globali sono impostate e contenute all'interno di ogni singolo context
.
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' }]
// Questo genererebbe un errore se il contesto viene creato da un oggetto contestualizzato.
// vm.constants.DONT_CONTEXTIFY consente la creazione di contesti con oggetti globali ordinari
// che possono essere congelati.
const freezeScript = new vm.Script('Object.freeze(globalThis); globalThis;');
const frozenContext = freezeScript.runInNewContext(vm.constants.DONT_CONTEXTIFY);
script.runInThisContext([options])
[Cronologia]
Versione | Modifiche |
---|---|
v6.3.0 | L'opzione breakOnSigint è ora supportata. |
v0.3.1 | Aggiunto in: v0.3.1 |
options
<Object>displayErrors
<boolean> Quandotrue
, se si verifica unError
durante la compilazione delcode
, la riga di codice che causa l'errore viene allegata alla traccia dello stack. Predefinito:true
.timeout
<integer> Specifica il numero di millisecondi per eseguirecode
prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà generato unError
. Questo valore deve essere un numero intero strettamente positivo.breakOnSigint
<boolean> Setrue
, la ricezione diSIGINT
(+) terminerà l'esecuzione e genererà unError
. I gestori esistenti per l'evento che sono stati allegati tramiteprocess.on('SIGINT')
vengono disabilitati durante l'esecuzione dello script, ma continuano a funzionare dopo. Predefinito:false
.
Restituisce: <any> il risultato dell'ultima istruzione eseguita nello script.
Esegue il codice compilato contenuto da vm.Script
nel contesto dell'oggetto global
corrente. L'esecuzione del codice non ha accesso all'ambito locale, ma ha accesso all'oggetto global
corrente.
L'esempio seguente compila il codice che incrementa una variabile global
quindi esegue quel codice più volte:
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
Aggiunto in: v19.1.0, v18.13.0
Quando lo script viene compilato da una sorgente che contiene un commento magico di source map, questa proprietà verrà impostata sull'URL della source map.
import vm from 'node:vm';
const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`);
console.log(script.sourceMapURL);
// Prints: sourcemap.json
const vm = require('node:vm');
const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`);
console.log(script.sourceMapURL);
// Prints: sourcemap.json
Classe: vm.Module
Aggiunto in: v13.0.0, v12.16.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1 - Sperimentale
Questa funzionalità è disponibile solo con il flag di comando --experimental-vm-modules
abilitato.
La classe vm.Module
fornisce un'interfaccia di basso livello per l'utilizzo dei moduli ECMAScript nei contesti VM. È la controparte della classe vm.Script
che rispecchia da vicino i Module Record come definiti nella specifica ECMAScript.
A differenza di vm.Script
tuttavia, ogni oggetto vm.Module
è vincolato a un contesto dalla sua creazione. Le operazioni sugli oggetti vm.Module
sono intrinsecamente asincrone, in contrasto con la natura sincrona degli oggetti vm.Script
. L'uso di funzioni 'async' può aiutare a manipolare gli oggetti vm.Module
.
L'utilizzo di un oggetto vm.Module
richiede tre passaggi distinti: creazione/analisi, collegamento e valutazione. Questi tre passaggi sono illustrati nel seguente esempio.
Questa implementazione si trova a un livello inferiore rispetto al caricatore di moduli ECMAScript. Inoltre, non c'è ancora modo di interagire con il Loader, anche se il supporto è pianificato.
import vm from 'node:vm';
const contextifiedObject = vm.createContext({
secret: 42,
print: console.log,
});
// Passaggio 1
//
// Crea un modulo costruendo un nuovo oggetto `vm.SourceTextModule`. Questo
// analizza il testo sorgente fornito, generando un `SyntaxError` se qualcosa va
// storto. Per impostazione predefinita, un modulo viene creato nel contesto principale. Ma qui, noi
// specifichiamo `contextifiedObject` come il contesto a cui appartiene questo modulo.
//
// Qui, tentiamo di ottenere l'esportazione predefinita dal modulo "foo" e
// metterla nel binding locale "secret".
const bar = new vm.SourceTextModule(`
import s from 'foo';
s;
print(s);
`, { context: contextifiedObject });
// Passaggio 2
//
// "Collega" le dipendenze importate di questo modulo ad esso.
//
// Il callback di collegamento fornito (il "linker") accetta due argomenti: il
// modulo padre (`bar` in questo caso) e la stringa che è lo specificatore di
// del modulo importato. Il callback dovrebbe restituire un modulo che
// corrisponde allo specificatore fornito, con determinati requisiti documentati
// in `module.link()`.
//
// Se il collegamento non è iniziato per il modulo restituito, lo stesso linker
// il callback verrà chiamato sul modulo restituito.
//
// Anche i moduli di livello superiore senza dipendenze devono essere collegati esplicitamente. Il
// il callback fornito non verrebbe mai chiamato, tuttavia.
//
// Il metodo link() restituisce una Promise che verrà risolta quando tutte le
// Promises restituite dal linker si risolvono.
//
// Nota: questo è un esempio artificioso in quanto la funzione linker crea un nuovo
// modulo "foo" ogni volta che viene chiamato. In un sistema di moduli completo, a
// la cache verrebbe probabilmente utilizzata per evitare moduli duplicati.
async function linker(specifier, referencingModule) {
if (specifier === 'foo') {
return new vm.SourceTextModule(`
// La variabile "secret" si riferisce alla variabile globale che abbiamo aggiunto a
// "contextifiedObject" quando si crea il contesto.
export default secret;
`, { context: referencingModule.context });
// Anche l'utilizzo di `contextifiedObject` invece di `referencingModule.context`
// qui funzionerebbe bene.
}
throw new Error(`Impossibile risolvere la dipendenza: ${specifier}`);
}
await bar.link(linker);
// Passaggio 3
//
// Valuta il modulo. Il metodo evaluate() restituisce una promise che
// si risolverà dopo che il modulo ha terminato la valutazione.
// Stampa 42.
await bar.evaluate();
const vm = require('node:vm');
const contextifiedObject = vm.createContext({
secret: 42,
print: console.log,
});
(async () => {
// Passaggio 1
//
// Crea un modulo costruendo un nuovo oggetto `vm.SourceTextModule`. Questo
// analizza il testo sorgente fornito, generando un `SyntaxError` se qualcosa va
// storto. Per impostazione predefinita, un modulo viene creato nel contesto principale. Ma qui, noi
// specifichiamo `contextifiedObject` come il contesto a cui appartiene questo modulo.
//
// Qui, tentiamo di ottenere l'esportazione predefinita dal modulo "foo" e
// metterla nel binding locale "secret".
const bar = new vm.SourceTextModule(`
import s from 'foo';
s;
print(s);
`, { context: contextifiedObject });
// Passaggio 2
//
// "Collega" le dipendenze importate di questo modulo ad esso.
//
// Il callback di collegamento fornito (il "linker") accetta due argomenti: il
// modulo padre (`bar` in questo caso) e la stringa che è lo specificatore di
// del modulo importato. Il callback dovrebbe restituire un modulo che
// corrisponde allo specificatore fornito, con determinati requisiti documentati
// in `module.link()`.
//
// Se il collegamento non è iniziato per il modulo restituito, lo stesso linker
// il callback verrà chiamato sul modulo restituito.
//
// Anche i moduli di livello superiore senza dipendenze devono essere collegati esplicitamente. Il
// il callback fornito non verrebbe mai chiamato, tuttavia.
//
// Il metodo link() restituisce una Promise che verrà risolta quando tutte le
// Promises restituite dal linker si risolvono.
//
// Nota: questo è un esempio artificioso in quanto la funzione linker crea un nuovo
// modulo "foo" ogni volta che viene chiamato. In un sistema di moduli completo, a
// la cache verrebbe probabilmente utilizzata per evitare moduli duplicati.
async function linker(specifier, referencingModule) {
if (specifier === 'foo') {
return new vm.SourceTextModule(`
// La variabile "secret" si riferisce alla variabile globale che abbiamo aggiunto a
// "contextifiedObject" quando si crea il contesto.
export default secret;
`, { context: referencingModule.context });
// Anche l'utilizzo di `contextifiedObject` invece di `referencingModule.context`
// qui funzionerebbe bene.
}
throw new Error(`Impossibile risolvere la dipendenza: ${specifier}`);
}
await bar.link(linker);
// Passaggio 3
//
// Valuta il modulo. Il metodo evaluate() restituisce una promise che
// si risolverà dopo che il modulo ha terminato la valutazione.
// Stampa 42.
await bar.evaluate();
})();
module.dependencySpecifiers
Gli specificatori di tutte le dipendenze di questo modulo. L'array restituito è bloccato per impedire qualsiasi modifica.
Corrisponde al campo [[RequestedModules]]
di Cyclic Module Record nella specifica ECMAScript.
module.error
Se module.status
è 'errored'
, questa proprietà contiene l'eccezione lanciata dal modulo durante la valutazione. Se lo stato è diverso, l'accesso a questa proprietà comporterà il lancio di un'eccezione.
Il valore undefined
non può essere utilizzato per i casi in cui non vi è un'eccezione lanciata a causa di una possibile ambiguità con throw undefined;
.
Corrisponde al campo [[EvaluationError]]
di Cyclic Module Record nella specifica ECMAScript.
module.evaluate([options])
options
<Object>timeout
<integer> Specifica il numero di millisecondi da valutare prima di terminare l'esecuzione. Se l'esecuzione viene interrotta, verrà lanciato unError
. Questo valore deve essere un intero strettamente positivo.breakOnSigint
<boolean> Setrue
, la ricezione diSIGINT
(+) terminerà l'esecuzione e lancerà unError
. I gestori esistenti per l'evento che sono stati collegati tramiteprocess.on('SIGINT')
vengono disabilitati durante l'esecuzione dello script, ma continuano a funzionare successivamente. Predefinito:false
.
Restituisce: <Promise> Si completa con
undefined
in caso di successo.
Valuta il modulo.
Questo deve essere chiamato dopo che il modulo è stato collegato; altrimenti verrà rifiutato. Potrebbe essere chiamato anche quando il modulo è già stato valutato, nel qual caso non farà nulla se la valutazione iniziale si è conclusa con successo (module.status
è 'evaluated'
) oppure rilancerà l'eccezione che la valutazione iniziale ha comportato (module.status
è 'errored'
).
Questo metodo non può essere chiamato mentre il modulo è in fase di valutazione (module.status
è 'evaluating'
).
Corrisponde al campo Evaluate() concrete method di Cyclic Module Record nella specifica ECMAScript.
module.identifier
L'identificatore del modulo corrente, come impostato nel costruttore.
module.link(linker)
[Cronologia]
Versione | Modifiche |
---|---|
v21.1.0, v20.10.0, v18.19.0 | L'opzione extra.assert è rinominata in extra.attributes . Il nome precedente è ancora fornito per compatibilità con le versioni precedenti. |
linker
<Function>specifier
<string> Lo specificatore del modulo richiesto:referencingModule
<vm.Module> L'oggettoModule
su cui viene chiamatolink()
.extra
<Object>attributes
<Object> I dati dell'attributo: Secondo ECMA-262, ci si aspetta che gli host attivino un errore se è presente un attributo non supportato.assert
<Object> Alias perextra.attributes
.Restituisce: <vm.Module> | <Promise>
Restituisce: <Promise>
Collega le dipendenze del modulo. Questo metodo deve essere chiamato prima della valutazione e può essere chiamato una sola volta per modulo.
Si prevede che la funzione restituisca un oggetto Module
o una Promise
che alla fine si risolva in un oggetto Module
. Il Module
restituito deve soddisfare i seguenti due invarianti:
- Deve appartenere allo stesso contesto del
Module
padre. - Il suo
status
non deve essere'errored'
.
Se lo status
del Module
restituito è 'unlinked'
, questo metodo verrà chiamato ricorsivamente sul Module
restituito con la stessa funzione linker
fornita.
link()
restituisce una Promise
che verrà risolta quando tutte le istanze di collegamento si risolvono in un Module
valido, oppure rifiutata se la funzione linker genera un'eccezione o restituisce un Module
non valido.
La funzione linker corrisponde approssimativamente all'operazione astratta HostResolveImportedModule definita dall'implementazione nella specifica ECMAScript, con alcune differenze fondamentali:
- La funzione linker può essere asincrona mentre HostResolveImportedModule è sincrona.
L'implementazione effettiva di HostResolveImportedModule utilizzata durante il collegamento del modulo è quella che restituisce i moduli collegati durante il collegamento. Poiché a quel punto tutti i moduli sarebbero già stati completamente collegati, l'implementazione di HostResolveImportedModule è completamente sincrona per specifica.
Corrisponde al campo Link() concrete method di Cyclic Module Record nella specifica ECMAScript.
module.namespace
L'oggetto namespace del modulo. Questo è disponibile solo dopo che il collegamento (module.link()
) è stato completato.
Corrisponde all'operazione astratta GetModuleNamespace nella specifica ECMAScript.
module.status
Lo stato attuale del modulo. Sarà uno tra:
'unlinked'
:module.link()
non è ancora stato chiamato.'linking'
:module.link()
è stato chiamato, ma non tutte le Promise restituite dalla funzione di collegamento sono state ancora risolte.'linked'
: Il modulo è stato collegato con successo e tutte le sue dipendenze sono collegate, mamodule.evaluate()
non è ancora stato chiamato.'evaluating'
: Il modulo è in fase di valutazione tramite unmodule.evaluate()
su se stesso o su un modulo padre.'evaluated'
: Il modulo è stato valutato con successo.'errored'
: Il modulo è stato valutato, ma è stata generata un'eccezione.
Oltre a 'errored'
, questa stringa di stato corrisponde al campo [[Status]]
del Cyclic Module Record della specifica. 'errored'
corrisponde a 'evaluated'
nella specifica, ma con [[EvaluationError]]
impostato su un valore che non è undefined
.
Classe: vm.SourceTextModule
Aggiunto in: v9.6.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1 - Sperimentale
Questa funzionalità è disponibile solo con il flag di comando --experimental-vm-modules
abilitato.
- Estende: <vm.Module>
La classe vm.SourceTextModule
fornisce il Source Text Module Record come definito nella specifica ECMAScript.
new vm.SourceTextModule(code[, options])
[Cronologia]
Versione | Modifiche |
---|---|
v17.0.0, v16.12.0 | Aggiunto il supporto per gli attributi di importazione al parametro importModuleDynamically . |
code
<string> Codice del modulo JavaScript da analizzareoptions
identifier
<string> Stringa utilizzata nelle stack trace. Predefinito:'vm:module(i)'
dovei
è un indice crescente specifico del contesto.cachedData
<Buffer> | <TypedArray> | <DataView> Fornisce unBuffer
oTypedArray
, oDataView
opzionale con i dati della cache del codice V8 per la sorgente fornita. Ilcode
deve essere lo stesso del modulo da cui è stato creato questocachedData
.context
<Object> L'oggetto contestualizzato come restituito dal metodovm.createContext()
, per compilare e valutare questoModule
in. Se non viene specificato alcun contesto, il modulo viene valutato nel contesto di esecuzione corrente.lineOffset
<integer> Specifica l'offset del numero di riga visualizzato nelle stack trace prodotte da questoModule
. Predefinito:0
.columnOffset
<integer> Specifica l'offset del numero di colonna della prima riga visualizzato nelle stack trace prodotte da questoModule
. Predefinito:0
.initializeImportMeta
<Function> Chiamato durante la valutazione di questoModule
per inizializzareimport.meta
.meta
<import.meta>module
<vm.SourceTextModule>importModuleDynamically
<Function> Utilizzato per specificare come i moduli devono essere caricati durante la valutazione di questo modulo quando viene chiamatoimport()
. Questa opzione fa parte dell'API dei moduli sperimentali. Si sconsiglia di utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto diimport()
dinamico nelle API di compilazione.
Crea una nuova istanza di SourceTextModule
.
Le proprietà assegnate all'oggetto import.meta
che sono oggetti possono consentire al modulo di accedere a informazioni al di fuori del context
specificato. Utilizzare vm.runInContext()
per creare oggetti in un contesto specifico.
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) {
// Note: this object is created in the top context. As such,
// Object.getPrototypeOf(import.meta.prop) points to the
// Object.prototype in the top context rather than that in
// the contextified object.
meta.prop = {};
},
});
// Since module has no dependencies, the linker function will never be called.
await module.link(() => {});
await module.evaluate();
// Now, Object.prototype.secret will be equal to 42.
//
// To fix this problem, replace
// meta.prop = {};
// above with
// 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) {
// Note: this object is created in the top context. As such,
// Object.getPrototypeOf(import.meta.prop) points to the
// Object.prototype in the top context rather than that in
// the contextified object.
meta.prop = {};
},
});
// Since module has no dependencies, the linker function will never be called.
await module.link(() => {});
await module.evaluate();
// Now, Object.prototype.secret will be equal to 42.
//
// To fix this problem, replace
// meta.prop = {};
// above with
// meta.prop = vm.runInContext('{}', contextifiedObject);
})();
sourceTextModule.createCachedData()
Aggiunto in: v13.7.0, v12.17.0
- Restituisce: <Buffer>
Crea una cache di codice che può essere utilizzata con l'opzione cachedData
del costruttore SourceTextModule
. Restituisce un Buffer
. Questo metodo può essere chiamato un numero qualsiasi di volte prima che il modulo sia stato valutato.
La cache di codice di SourceTextModule
non contiene alcuno stato osservabile di JavaScript. La cache di codice è sicura per essere salvata insieme al codice sorgente e utilizzata per costruire nuove istanze di SourceTextModule
più volte.
Le funzioni nel sorgente SourceTextModule
possono essere contrassegnate come compilate in modo pigro e non vengono compilate alla costruzione di SourceTextModule
. Queste funzioni verranno compilate quando vengono invocate per la prima volta. La cache di codice serializza i metadati che V8 attualmente conosce su SourceTextModule
che può utilizzare per velocizzare le compilazioni future.
// Crea un modulo iniziale
const module = new vm.SourceTextModule('const a = 1;');
// Crea dati memorizzati nella cache da questo modulo
const cachedData = module.createCachedData();
// Crea un nuovo modulo utilizzando i dati memorizzati nella cache. Il codice deve essere lo stesso.
const module2 = new vm.SourceTextModule('const a = 1;', { cachedData });
Classe: vm.SyntheticModule
Aggiunto in: v13.0.0, v12.16.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1 - Sperimentale
Questa funzionalità è disponibile solo con il flag di comando --experimental-vm-modules
abilitato.
- Estende: <vm.Module>
La classe vm.SyntheticModule
fornisce il Record del modulo sintetico come definito nella specifica WebIDL. Lo scopo dei moduli sintetici è fornire un'interfaccia generica per esporre sorgenti non JavaScript ai grafi dei moduli ECMAScript.
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);
});
// Utilizza `module` nel collegamento...
new vm.SyntheticModule(exportNames, evaluateCallback[, options])
Aggiunto in: v13.0.0, v12.16.0
exportNames
<string[]> Array di nomi che verranno esportati dal modulo.evaluateCallback
<Function> Chiamata quando il modulo viene valutato.options
identifier
<string> Stringa utilizzata nelle stack trace. Predefinito:'vm:module(i)'
dovei
è un indice crescente specifico del contesto.context
<Object> L'oggetto contestualizzato come restituito dal metodovm.createContext()
, per compilare e valutare questoModule
in.
Crea una nuova istanza SyntheticModule
.
Gli oggetti assegnati alle esportazioni di questa istanza possono consentire agli importatori del modulo di accedere a informazioni al di fuori del context
specificato. Utilizzare vm.runInContext()
per creare oggetti in un contesto specifico.
syntheticModule.setExport(name, value)
Aggiunto in: v13.0.0, v12.16.0
name
<string> Nome dell'esportazione da impostare.value
<any> Il valore a cui impostare l'esportazione.
Questo metodo viene utilizzato dopo che il modulo è collegato per impostare i valori delle esportazioni. Se viene chiamato prima che il modulo sia collegato, verrà generato un errore ERR_VM_MODULE_STATUS
.
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]])
[Cronologia]
Versione | Modifiche |
---|---|
v21.7.0, v20.12.0 | Aggiunto il supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v19.6.0, v18.15.0 | Il valore restituito ora include cachedDataRejected con la stessa semantica della versione vm.Script se è stata passata l'opzione cachedData . |
v17.0.0, v16.12.0 | Aggiunto il supporto per gli attributi di importazione al parametro importModuleDynamically . |
v15.9.0 | Aggiunta nuovamente l'opzione importModuleDynamically . |
v14.3.0 | Rimozione di importModuleDynamically a causa di problemi di compatibilità. |
v14.1.0, v13.14.0 | L'opzione importModuleDynamically è ora supportata. |
v10.10.0 | Aggiunto in: v10.10.0 |
code
<stringa> Il corpo della funzione da compilare.params
<stringa[]> Un array di stringhe contenente tutti i parametri per la funzione.options
<Oggetto>filename
<stringa> Specifica il nome del file utilizzato nelle stack trace prodotte da questo script. Predefinito:''
.lineOffset
<numero> Specifica l'offset del numero di riga visualizzato nelle stack trace prodotte da questo script. Predefinito:0
.columnOffset
<numero> Specifica l'offset del numero di colonna della prima riga visualizzato nelle stack trace prodotte da questo script. Predefinito:0
.cachedData
<Buffer> | <TypedArray> | <DataView> Fornisce unBuffer
oTypedArray
opzionale, oppureDataView
con i dati della cache del codice V8 per l'origine fornita. Questo deve essere prodotto da una precedente chiamata avm.compileFunction()
con lo stessocode
eparams
.produceCachedData
<booleano> Specifica se produrre nuovi dati della cache. Predefinito:false
.parsingContext
<Oggetto> L'oggetto contestualizzato in cui la suddetta funzione deve essere compilata.contextExtensions
<Oggetto[]> Un array contenente una raccolta di estensioni del contesto (oggetti che racchiudono l'ambito corrente) da applicare durante la compilazione. Predefinito:[]
.
importModuleDynamically
<Funzione> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Utilizzato per specificare come i moduli devono essere caricati durante la valutazione di questa funzione quando viene chiamatoimport()
. Questa opzione fa parte dell'API dei moduli sperimentali. Si sconsiglia di utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto diimport()
dinamico nelle API di compilazione.Restituisce: <Funzione>
Compila il codice specificato nel contesto fornito (se non viene fornito alcun contesto, viene utilizzato il contesto corrente) e lo restituisce racchiuso all'interno di una funzione con i params
specificati.
vm.constants
Aggiunto in: v21.7.0, v20.12.0
Restituisce un oggetto contenente costanti comunemente utilizzate per le operazioni VM.
vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER
Aggiunto in: v21.7.0, v20.12.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1.1 - Sviluppo attivo
Una costante che può essere utilizzata come opzione importModuleDynamically
per vm.Script
e vm.compileFunction()
in modo che Node.js utilizzi il loader ESM predefinito dal contesto principale per caricare il modulo richiesto.
Per informazioni dettagliate, vedere Supporto di import()
dinamico nelle API di compilazione.
vm.createContext([contextObject[, options]])
[Cronologia]
Versione | Modifiche |
---|---|
v22.8.0, v20.18.0 | L'argomento contextObject ora accetta vm.constants.DONT_CONTEXTIFY . |
v21.7.0, v20.12.0 | Aggiunto il supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v21.2.0, v20.11.0 | L'opzione importModuleDynamically è ora supportata. |
v14.6.0 | L'opzione microtaskMode è ora supportata. |
v10.0.0 | Il primo argomento non può più essere una funzione. |
v10.0.0 | L'opzione codeGeneration è ora supportata. |
v0.3.1 | Aggiunto in: v0.3.1 |
contextObject
<Object> | <vm.constants.DONT_CONTEXTIFY> | <undefined> Siavm.constants.DONT_CONTEXTIFY
o un oggetto che sarà contestualizzato. Seundefined
, verrà creato un oggetto contestualizzato vuoto per compatibilità con le versioni precedenti.options
<Object>name
<string> Nome leggibile del contesto appena creato. Predefinito:'VM Context i'
, dovei
è un indice numerico crescente del contesto creato.origin
<string> Origine corrispondente al contesto appena creato a scopo di visualizzazione. L'origine deve essere formattata come un URL, ma solo con lo schema, l'host e la porta (se necessario), come il valore della proprietàurl.origin
di un oggettoURL
. In particolare, questa stringa deve omettere la barra finale, poiché denota un percorso. Predefinito:''
.codeGeneration
<Object>strings
<boolean> Se impostato su false, qualsiasi chiamata aeval
o costruttori di funzioni (Function
,GeneratorFunction
, ecc.) genererà unEvalError
. Predefinito:true
.wasm
<boolean> Se impostato su false, qualsiasi tentativo di compilare un modulo WebAssembly genererà unWebAssembly.CompileError
. Predefinito:true
.microtaskMode
<string> Se impostato suafterEvaluate
, i microtask (task pianificati tramitePromise
easync function
) verranno eseguiti immediatamente dopo che uno script è stato eseguito tramitescript.runInContext()
. Sono inclusi negli ambititimeout
ebreakOnSigint
in quel caso.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Utilizzato per specificare come i moduli devono essere caricati quandoimport()
viene chiamato in questo contesto senza uno script o modulo di riferimento. Questa opzione fa parte dell'API dei moduli sperimentali. Si sconsiglia di utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto diimport()
dinamico nelle API di compilazione.
Restituisce: <Object> oggetto contestualizzato.
Se il dato contextObject
è un oggetto, il metodo vm.createContext()
preparerà quell'oggetto e restituirà un riferimento ad esso in modo che possa essere utilizzato nelle chiamate a vm.runInContext()
o script.runInContext()
. All'interno di tali script, l'oggetto globale verrà incapsulato dal contextObject
, mantenendo tutte le sue proprietà esistenti ma avendo anche gli oggetti e le funzioni built-in che qualsiasi oggetto globale standard ha. Al di fuori degli script eseguiti dal modulo vm, le variabili globali rimarranno invariate.
const vm = require('node:vm');
global.globalVar = 3;
const context = { globalVar: 1 };
vm.createContext(context);
vm.runInContext('globalVar *= 2;', context);
console.log(context);
// Stampa: { globalVar: 2 }
console.log(global.globalVar);
// Stampa: 3
Se contextObject
viene omesso (o passato esplicitamente come undefined
), verrà restituito un nuovo oggetto contestualizzato vuoto.
Quando l'oggetto globale nel contesto appena creato è contestualizzato, ha alcune peculiarità rispetto agli oggetti globali ordinari. Ad esempio, non può essere congelato. Per creare un contesto senza le peculiarità di contestualizzazione, passa vm.constants.DONT_CONTEXTIFY
come argomento contextObject
. Vedere la documentazione di vm.constants.DONT_CONTEXTIFY
per i dettagli.
Il metodo vm.createContext()
è principalmente utile per creare un singolo contesto che può essere utilizzato per eseguire più script. Ad esempio, se si emula un browser web, il metodo può essere utilizzato per creare un singolo contesto che rappresenta l'oggetto globale di una finestra, quindi eseguire tutti i tag \<script\>
insieme all'interno di quel contesto.
Il name
e l'origin
forniti del contesto sono resi visibili tramite l'API Inspector.
vm.isContext(object)
Aggiunto in: v0.11.7
Restituisce true
se l'oggetto object
dato è stato contestualizzato usando vm.createContext()
, o se è l'oggetto globale di un contesto creato usando vm.constants.DONT_CONTEXTIFY
.
vm.measureMemory([options])
Aggiunto in: v13.10.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1 - Sperimentale
Misura la memoria conosciuta da V8 e utilizzata da tutti i contesti conosciuti dall'isolato V8 corrente, o dal contesto principale.
options
<Object> Opzionale.mode
<string> O'summary'
o'detailed'
. Nella modalità summary, verrà restituita solo la memoria misurata per il contesto principale. Nella modalità detailed, verrà restituita la memoria misurata per tutti i contesti conosciuti dall'isolato V8 corrente. Predefinito:'summary'
execution
<string> O'default'
o'eager'
. Con l'esecuzione predefinita, la promise non si risolverà fino all'avvio della successiva garbage collection pianificata, il che potrebbe richiedere un po' di tempo (o mai se il programma esce prima della prossima GC). Con l'esecuzione eager, la GC verrà avviata immediatamente per misurare la memoria. Predefinito:'default'
Restituisce: <Promise> Se la memoria viene misurata correttamente, la promise si risolverà con un oggetto contenente informazioni sull'utilizzo della memoria. Altrimenti verrà rifiutata con un errore
ERR_CONTEXT_NOT_INITIALIZED
.
Il formato dell'oggetto con cui la Promise restituita potrebbe risolversi è specifico del motore V8 e potrebbe cambiare da una versione di V8 all'altra.
Il risultato restituito è diverso dalle statistiche restituite da v8.getHeapSpaceStatistics()
in quanto vm.measureMemory()
misura la memoria raggiungibile da ciascun contesto specifico di V8 nell'istanza corrente del motore V8, mentre il risultato di v8.getHeapSpaceStatistics()
misura la memoria occupata da ciascuno spazio heap nell'istanza V8 corrente.
const vm = require('node:vm');
// Misura la memoria utilizzata dal contesto principale.
vm.measureMemory({ mode: 'summary' })
// Questo è lo stesso di vm.measureMemory()
.then((result) => {
// Il formato corrente è:
// {
// total: {
// jsMemoryEstimate: 2418479, jsMemoryRange: [ 2418479, 2745799 ]
// }
// }
console.log(result);
});
const context = vm.createContext({ a: 1 });
vm.measureMemory({ mode: 'detailed', execution: 'eager' })
.then((result) => {
// Fare riferimento al contesto qui in modo che non venga
// raccolto dalla GC fino al completamento della misurazione.
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])
[Cronologia]
Versione | Modifiche |
---|---|
v21.7.0, v20.12.0 | Aggiunto il supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Aggiunto il supporto per gli attributi di importazione al parametro importModuleDynamically . |
v6.3.0 | L'opzione breakOnSigint è ora supportata. |
v0.3.1 | Aggiunto in: v0.3.1 |
code
<stringa> Il codice JavaScript da compilare ed eseguire.contextifiedObject
<Oggetto> L'oggetto contestualizzato che verrà utilizzato comeglobal
quando ilcode
viene compilato ed eseguito.options
<Oggetto> | <stringa>filename
<stringa> Specifica il nome del file utilizzato nelle stack trace prodotte da questo script. Predefinito:'evalmachine.\<anonymous\>'
.lineOffset
<numero> Specifica l'offset del numero di riga visualizzato nelle stack trace prodotte da questo script. Predefinito:0
.columnOffset
<numero> Specifica l'offset del numero di colonna della prima riga visualizzato nelle stack trace prodotte da questo script. Predefinito:0
.displayErrors
<booleano> Quandotrue
, se si verifica unError
durante la compilazione delcode
, la riga di codice che causa l'errore viene allegata alla stack trace. Predefinito:true
.timeout
<intero> Specifica il numero di millisecondi per eseguirecode
prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà generato unError
. Questo valore deve essere un numero intero strettamente positivo.breakOnSigint
<booleano> Setrue
, la ricezione diSIGINT
(+) terminerà l'esecuzione e genererà unError
. I gestori esistenti per l'evento che sono stati allegati tramiteprocess.on('SIGINT')
vengono disabilitati durante l'esecuzione dello script, ma continuano a funzionare successivamente. Predefinito:false
.cachedData
<Buffer> | <TypedArray> | <DataView> Fornisce unBuffer
oTypedArray
oDataView
facoltativo con i dati della cache del codice V8 per la sorgente fornita.importModuleDynamically
<Funzione> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Utilizzato per specificare come i moduli devono essere caricati durante la valutazione di questo script quando viene chiamatoimport()
. Questa opzione fa parte dell'API dei moduli sperimentali. Si sconsiglia di utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto diimport()
dinamico nelle API di compilazione.
Il metodo vm.runInContext()
compila code
, lo esegue all'interno del contesto di contextifiedObject
, quindi restituisce il risultato. L'esecuzione del codice non ha accesso all'ambito locale. L'oggetto contextifiedObject
deve essere stato precedentemente contestualizzato utilizzando il metodo vm.createContext()
.
Se options
è una stringa, specifica il nome del file.
L'esempio seguente compila ed esegue script diversi utilizzando un singolo oggetto contestualizzato:
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);
// Prints: { globalVar: 1024 }
vm.runInNewContext(code[, contextObject[, options]])
[Cronologia]
Versione | Modifiche |
---|---|
v22.8.0, v20.18.0 | L'argomento contextObject ora accetta vm.constants.DONT_CONTEXTIFY . |
v21.7.0, v20.12.0 | Aggiunto il supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Aggiunto il supporto per gli attributi di importazione al parametro importModuleDynamically . |
v14.6.0 | L'opzione microtaskMode è ora supportata. |
v10.0.0 | L'opzione contextCodeGeneration è ora supportata. |
v6.3.0 | L'opzione breakOnSigint è ora supportata. |
v0.3.1 | Aggiunto in: v0.3.1 |
code
<stringa> Il codice JavaScript da compilare ed eseguire.contextObject
<Oggetto> | <vm.constants.DONT_CONTEXTIFY> | <undefined> Siavm.constants.DONT_CONTEXTIFY
che un oggetto che verrà contestualizzato. Seundefined
, verrà creato un oggetto contestualizzato vuoto per retrocompatibilità.filename
<stringa> Specifica il nome del file utilizzato nelle stack trace prodotte da questo script. Predefinito:'evalmachine.\<anonymous\>'
.lineOffset
<numero> Specifica l'offset del numero di riga visualizzato nelle stack trace prodotte da questo script. Predefinito:0
.columnOffset
<numero> Specifica l'offset del numero di colonna della prima riga visualizzato nelle stack trace prodotte da questo script. Predefinito:0
.displayErrors
<booleano> Quandotrue
, se si verifica unError
durante la compilazione delcode
, la riga di codice che causa l'errore viene allegata alla stack trace. Predefinito:true
.timeout
<intero> Specifica il numero di millisecondi per eseguire ilcode
prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà generato unError
. Questo valore deve essere un intero strettamente positivo.breakOnSigint
<booleano> Setrue
, la ricezione diSIGINT
(+) terminerà l'esecuzione e genererà unError
. I gestori esistenti per l'evento che sono stati allegati tramiteprocess.on('SIGINT')
sono disabilitati durante l'esecuzione dello script, ma continuano a funzionare dopo. Predefinito:false
.contextName
<stringa> Nome leggibile dal utente del contesto appena creato. Predefinito:'VM Context i'
, dovei
è un indice numerico crescente del contesto creato.contextOrigin
<stringa> Origine corrispondente al contesto appena creato a scopo di visualizzazione. L'origine deve essere formattata come un URL, ma solo con lo schema, l'host e la porta (se necessario), come il valore della proprietàurl.origin
di un oggettoURL
. In particolare, questa stringa deve omettere la barra finale, poiché denota un percorso. Predefinito:''
.contextCodeGeneration
<Oggetto>strings
<booleano> Se impostato su false, qualsiasi chiamata aeval
o costruttori di funzioni (Function
,GeneratorFunction
, ecc.) genererà unEvalError
. Predefinito:true
.wasm
<booleano> Se impostato su false, qualsiasi tentativo di compilare un modulo WebAssembly genererà unWebAssembly.CompileError
. Predefinito:true
.
cachedData
<Buffer> | <TypedArray> | <DataView> Fornisce unBuffer
oTypedArray
oDataView
opzionale con i dati della cache del codice V8 per l'origine fornita.importModuleDynamically
<Funzione> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Usato per specificare come i moduli devono essere caricati durante la valutazione di questo script quando viene chiamatoimport()
. Questa opzione fa parte dell'API dei moduli sperimentali. Si sconsiglia di utilizzarlo in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto diimport()
dinamico nelle API di compilazione.microtaskMode
<stringa> Se impostato suafterEvaluate
, le microtask (task pianificate tramitePromise
easync function
) verranno eseguite immediatamente dopo l'esecuzione dello script. In tal caso, sono inclusi negli ambititimeout
ebreakOnSigint
.
Restituisce: <any> il risultato dell'ultima istruzione eseguita nello script.
Questo metodo è una scorciatoia per (new vm.Script(code, options)).runInContext(vm.createContext(options), options)
. Se options
è una stringa, specifica il nome del file.
Fa diverse cose contemporaneamente:
L'esempio seguente compila ed esegue codice che incrementa una variabile globale e ne imposta una nuova. Queste variabili globali sono contenute in contextObject
.
const vm = require('node:vm');
const contextObject = {
animal: 'cat',
count: 2,
};
vm.runInNewContext('count += 1; name = "kitty"', contextObject);
console.log(contextObject);
// Prints: { animal: 'cat', count: 3, name: 'kitty' }
// This would throw if the context is created from a contextified object.
// vm.constants.DONT_CONTEXTIFY allows creating contexts with ordinary global objects that
// can be frozen.
const frozenContext = vm.runInNewContext('Object.freeze(globalThis); globalThis;', vm.constants.DONT_CONTEXTIFY);
vm.runInThisContext(code[, options])
[Cronologia]
Versione | Modifiche |
---|---|
v21.7.0, v20.12.0 | Aggiunto il supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Aggiunto il supporto per gli attributi di importazione al parametro importModuleDynamically . |
v6.3.0 | L'opzione breakOnSigint è ora supportata. |
v0.3.1 | Aggiunto in: v0.3.1 |
code
<string> Il codice JavaScript da compilare ed eseguire.filename
<string> Specifica il nome del file utilizzato negli stack trace prodotti da questo script. Predefinito:'evalmachine.\<anonymous\>'
.lineOffset
<number> Specifica l'offset del numero di riga visualizzato negli stack trace prodotti da questo script. Predefinito:0
.columnOffset
<number> Specifica l'offset del numero di colonna della prima riga visualizzato negli stack trace prodotti da questo script. Predefinito:0
.displayErrors
<boolean> Quandotrue
, se si verifica unError
durante la compilazione delcode
, la riga di codice che causa l'errore viene allegata allo stack trace. Predefinito:true
.timeout
<integer> Specifica il numero di millisecondi per eseguirecode
prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà generato unError
. Questo valore deve essere un numero intero strettamente positivo.breakOnSigint
<boolean> Setrue
, la ricezione diSIGINT
(+) terminerà l'esecuzione e genererà unError
. I gestori esistenti per l'evento che sono stati collegati tramiteprocess.on('SIGINT')
vengono disabilitati durante l'esecuzione dello script, ma continuano a funzionare successivamente. Predefinito:false
.cachedData
<Buffer> | <TypedArray> | <DataView> Fornisce unBuffer
oTypedArray
opzionale, oDataView
con i dati della cache del codice V8 per l'origine fornita.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Utilizzato per specificare come i moduli devono essere caricati durante la valutazione di questo script quando viene chiamatoimport()
. Questa opzione fa parte dell'API dei moduli sperimentali. Si sconsiglia di utilizzarlo in un ambiente di produzione. Per informazioni dettagliate, consulta Supporto dell'import()
dinamico nelle API di compilazione.
Returns: <any> il risultato dell'ultima istruzione eseguita nello script.
vm.runInThisContext()
compila code
, lo esegue nel contesto del global
corrente e restituisce il risultato. L'esecuzione del codice non ha accesso allo scope locale, ma ha accesso all'oggetto global
corrente.
Se options
è una stringa, specifica il nome del file.
L'esempio seguente illustra l'utilizzo sia di vm.runInThisContext()
sia della funzione JavaScript eval()
per eseguire lo stesso codice:
const vm = require('node:vm');
let localVar = 'initial value';
const vmResult = vm.runInThisContext('localVar = "vm";');
console.log(`vmResult: '${vmResult}', localVar: '${localVar}'`);
// Prints: vmResult: 'vm', localVar: 'initial value'
const evalResult = eval('localVar = "eval";');
console.log(`evalResult: '${evalResult}', localVar: '${localVar}'`);
// Prints: evalResult: 'eval', localVar: 'eval'
Poiché vm.runInThisContext()
non ha accesso allo scope locale, localVar
rimane invariato. Al contrario, eval()
ha accesso allo scope locale, quindi il valore di localVar
viene modificato. In questo modo, vm.runInThisContext()
è molto simile a una chiamata indiretta di eval()
, ad es. (0,eval)('code')
.
Esempio: Esecuzione di un server HTTP all'interno di una VM
Quando si utilizza script.runInThisContext()
o vm.runInThisContext()
, il codice viene eseguito all'interno del contesto globale V8 corrente. Il codice passato a questo contesto VM avrà il suo scope isolato.
Per eseguire un semplice server web utilizzando il modulo node:http
, il codice passato al contesto deve chiamare require('node:http')
da solo, oppure avere un riferimento al modulo node:http
passato ad esso. Ad esempio:
'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('Hello World\\n');
}).listen(8124);
console.log('Server running at http://127.0.0.1:8124/');
})`;
vm.runInThisContext(code)(require);
Il require()
nel caso sopra condivide lo stato con il contesto da cui viene passato. Ciò può introdurre rischi quando viene eseguito codice non affidabile, ad esempio alterando oggetti nel contesto in modi indesiderati.
Cosa significa "contestualizzare" un oggetto?
Tutto il JavaScript eseguito all'interno di Node.js viene eseguito nell'ambito di un "contesto". Secondo la Guida per l'Embedder di V8:
Quando il metodo vm.createContext()
viene chiamato con un oggetto, l'argomento contextObject
verrà utilizzato per avvolgere l'oggetto globale di una nuova istanza di un contesto V8 (se contextObject
è undefined
, verrà creato un nuovo oggetto dal contesto corrente prima che venga contestualizzato). Questo contesto V8 fornisce al code
eseguito utilizzando i metodi del modulo node:vm
un ambiente globale isolato all'interno del quale può operare. Il processo di creazione del contesto V8 e di associazione con il contextObject
nel contesto esterno è ciò che questo documento definisce "contestualizzare" l'oggetto.
La contestualizzazione introdurrebbe alcune stranezze al valore globalThis
nel contesto. Ad esempio, non può essere bloccato e non è uguale per riferimento al contextObject
nel contesto esterno.
const vm = require('node:vm');
// Un'opzione `contextObject` undefined rende l'oggetto globale contestualizzato.
const context = vm.createContext();
console.log(vm.runInContext('globalThis', context) === context); // false
// Un oggetto globale contestualizzato non può essere bloccato.
try {
vm.runInContext('Object.freeze(globalThis);', context);
} catch (e) {
console.log(e); // TypeError: Cannot freeze
}
console.log(vm.runInContext('globalThis.foo = 1; foo;', context)); // 1
Per creare un contesto con un oggetto globale ordinario e ottenere l'accesso a un proxy globale nel contesto esterno con meno stranezze, specifica vm.constants.DONT_CONTEXTIFY
come argomento contextObject
.
vm.constants.DONT_CONTEXTIFY
Quando utilizzata come argomento contextObject
nelle API vm, questa costante indica a Node.js di creare un contesto senza avvolgere il suo oggetto globale con un altro oggetto in modo specifico per Node.js. Di conseguenza, il valore globalThis
all'interno del nuovo contesto si comporterebbe in modo più simile a uno ordinario.
const vm = require('node:vm');
// Utilizza vm.constants.DONT_CONTEXTIFY per bloccare l'oggetto globale.
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
}
Quando vm.constants.DONT_CONTEXTIFY
viene utilizzato come argomento contextObject
per vm.createContext()
, l'oggetto restituito è un oggetto simile a un proxy per l'oggetto globale nel contesto appena creato con meno peculiarità specifiche di Node.js. È uguale al valore globalThis
nel nuovo contesto, può essere modificato dall'esterno del contesto e può essere utilizzato per accedere direttamente alle funzioni integrate nel nuovo contesto.
const vm = require('node:vm');
const context = vm.createContext(vm.constants.DONT_CONTEXTIFY);
// L'oggetto restituito è uguale a globalThis nel nuovo contesto.
console.log(vm.runInContext('globalThis', context) === context); // true
// Può essere utilizzato per accedere direttamente alle variabili globali nel nuovo contesto.
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
// Può essere bloccato e influisce sul contesto interno.
Object.freeze(context);
try {
vm.runInContext('baz = 1; baz;', context);
} catch (e) {
console.log(e); // Uncaught ReferenceError: baz is not defined
}
Interazioni di timeout con task asincroni e Promise
Promise
e async function
possono pianificare l'esecuzione di task asincroni da parte del motore JavaScript. Per impostazione predefinita, questi task vengono eseguiti dopo che tutte le funzioni JavaScript sullo stack corrente hanno terminato l'esecuzione. Ciò consente di eludere le funzionalità delle opzioni timeout
e breakOnSigint
.
Ad esempio, il seguente codice eseguito da vm.runInNewContext()
con un timeout di 5 millisecondi pianifica un ciclo infinito da eseguire dopo che una promise si è risolta. Il ciclo pianificato non viene mai interrotto dal timeout:
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 },
);
// Questo viene stampato *prima* di 'entering loop' (!)
console.log('done executing');
Questo può essere risolto passando microtaskMode: 'afterEvaluate'
al codice che crea il Context
:
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 questo caso, il microtask pianificato tramite promise.then()
verrà eseguito prima di tornare da vm.runInNewContext()
e verrà interrotto dalla funzionalità timeout
. Questo si applica solo al codice in esecuzione in un vm.Context
, quindi ad esempio vm.runInThisContext()
non accetta questa opzione.
I callback di Promise vengono inseriti nella coda dei microtask del contesto in cui sono stati creati. Ad esempio, se () =\> loop()
viene sostituito con solo loop
nell'esempio sopra, allora loop
verrà inserito nella coda globale dei microtask, perché è una funzione dal contesto esterno (principale), e quindi sarà anche in grado di eludere il timeout.
Se le funzioni di pianificazione asincrona come process.nextTick()
, queueMicrotask()
, setTimeout()
, setImmediate()
, ecc. vengono rese disponibili all'interno di un vm.Context
, le funzioni passate a esse verranno aggiunte alle code globali, che sono condivise da tutti i contesti. Pertanto, anche i callback passati a quelle funzioni non sono controllabili tramite il timeout.
Supporto di import()
dinamico nelle API di compilazione
Le seguenti API supportano un'opzione importModuleDynamically
per abilitare import()
dinamico nel codice compilato dal modulo vm.
new vm.Script
vm.compileFunction()
new vm.SourceTextModule
vm.runInThisContext()
vm.runInContext()
vm.runInNewContext()
vm.createContext()
Questa opzione fa ancora parte dell'API dei moduli sperimentali. Si sconsiglia di utilizzarla in un ambiente di produzione.
Quando l'opzione importModuleDynamically
non è specificata o è indefinita
Se questa opzione non è specificata, o se è undefined
, il codice contenente import()
può comunque essere compilato dalle API vm, ma quando il codice compilato viene eseguito ed effettivamente chiama import()
, il risultato verrà rifiutato con ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING
.
Quando importModuleDynamically
è vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER
Questa opzione non è attualmente supportata per vm.SourceTextModule
.
Con questa opzione, quando un import()
viene avviato nel codice compilato, Node.js utilizzerebbe il caricatore ESM predefinito dal contesto principale per caricare il modulo richiesto e restituirlo al codice in esecuzione.
Ciò consente l'accesso ai moduli integrati di Node.js come fs
o http
al codice in fase di compilazione. Se il codice viene eseguito in un contesto diverso, tenere presente che gli oggetti creati dai moduli caricati dal contesto principale provengono ancora dal contesto principale e non sono instanceof
delle classi integrate nel nuovo contesto.
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 caricato dal contesto principale non è un'istanza della classe Function
// nel nuovo contesto.
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 caricato dal contesto principale non è un'istanza della classe Function
// nel nuovo contesto.
script.runInNewContext().then(console.log);
Questa opzione consente anche allo script o alla funzione di caricare moduli utente:
import { Script, constants } from 'node:vm';
import { resolve } from 'node:path';
import { writeFileSync } from 'node:fs';
// Scrivi test.js e test.txt nella directory in cui si trova lo script corrente
// in esecuzione.
writeFileSync(resolve(import.meta.dirname, 'test.mjs'),
'export const filename = "./test.json";');
writeFileSync(resolve(import.meta.dirname, 'test.json'),
'{"hello": "world"}');
// Compila uno script che carica test.mjs e poi test.json
// come se lo script fosse posizionato nella stessa directory.
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');
// Scrivi test.js e test.txt nella directory in cui si trova lo script corrente
// in esecuzione.
writeFileSync(resolve(__dirname, 'test.mjs'),
'export const filename = "./test.json";');
writeFileSync(resolve(__dirname, 'test.json'),
'{"hello": "world"}');
// Compila uno script che carica test.mjs e poi test.json
// come se lo script fosse posizionato nella stessa directory.
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);
Ci sono alcune avvertenze con il caricamento dei moduli utente utilizzando il caricatore predefinito dal contesto principale:
Quando importModuleDynamically
è una funzione
Quando importModuleDynamically
è una funzione, verrà invocata quando import()
viene chiamato nel codice compilato per consentire agli utenti di personalizzare come il modulo richiesto deve essere compilato e valutato. Attualmente, l'istanza di Node.js deve essere avviata con il flag --experimental-vm-modules
affinché questa opzione funzioni. Se il flag non è impostato, questo callback verrà ignorato. Se il codice valutato chiama effettivamente import()
, il risultato verrà rifiutato con ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAG
.
Il callback importModuleDynamically(specifier, referrer, importAttributes)
ha la seguente firma:
specifier
<stringa> identificatore passato aimport()
referrer
<vm.Script> | <Funzione> | <vm.SourceTextModule> | <Oggetto> Il referrer è ilvm.Script
compilato pernew vm.Script
,vm.runInThisContext
,vm.runInContext
evm.runInNewContext
. È laFunzione
compilata pervm.compileFunction
, ilvm.SourceTextModule
compilato pernew vm.SourceTextModule
e l'Oggetto
di contesto pervm.createContext()
.importAttributes
<Oggetto> Il valore"with"
passato al parametro opzionaleoptionsExpression
, o un oggetto vuoto se non è stato fornito alcun valore.- Restituisce: <Oggetto Spazio dei Nomi Modulo> | <vm.Module> Si consiglia di restituire un
vm.Module
per sfruttare il tracciamento degli errori ed evitare problemi con gli spazi dei nomi che contengono esportazioni di funzionithen
.
// Questo script deve essere eseguito con --experimental-vm-modules.
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); // Lo script compilato
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' } }
// Questo script deve essere eseguito con --experimental-vm-modules.
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); // Lo script compilato
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' } }
})();