VM (esecuzione di JavaScript)
[Stabile: 2 - Stabile]
Stabile: 2 Stabilità: 2 - Stabile
Codice sorgente: lib/vm.js
Il modulo node:vm
permette 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 è quello di eseguire il codice in un diverso contesto V8. Questo significa che il codice invocato ha un oggetto globale diverso dal codice che lo invoca.
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é questo è 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 è definita.
Classe: vm.Script
Aggiunta 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 supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Aggiunto supporto per 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 | Aggiunta in: v0.3.1 |
code
<string> Il codice JavaScript da compilare.options
<Object> | <string>filename
<string> Specifica il nome del file utilizzato nelle tracce dello stack prodotte da questo script. Default:'evalmachine.\<anonymous\>'
.lineOffset
<number> Specifica l'offset del numero di riga che viene visualizzato nelle tracce dello stack prodotte da questo script. Default:0
.columnOffset
<number> Specifica l'offset del numero di colonna della prima riga che viene visualizzato nelle tracce dello stack prodotte da questo script. Default:0
.cachedData
<Buffer> | <TypedArray> | <DataView> Fornisce unBuffer
oTypedArray
, oDataView
opzionale con i dati della cache del codice di V8 per la sorgente fornita. Quando fornito, il valorecachedDataRejected
sarà impostato sutrue
ofalse
a seconda dell'accettazione dei dati da parte di V8.produceCachedData
<boolean> Quandotrue
e non è presentecachedData
, 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
sarà impostato sutrue
ofalse
a seconda che i dati della cache del codice siano prodotti correttamente. Questa opzione è deprecata a favore discript.createCachedData()
. Default:false
.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Usato per specificare come i moduli dovrebbero 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.
Se options
è una stringa, allora specifica il nome del file.
La creazione di un nuovo oggetto vm.Script
compila code
ma non lo esegue. Lo vm.Script
compilato può essere eseguito successivamente più volte. Il code
non è legato ad alcun oggetto globale; piuttosto, è legato prima di ogni esecuzione, solo per quell'esecuzione.
script.cachedDataRejected
Aggiunto in: v5.7.0
Quando cachedData
viene fornito per creare vm.Script
, questo valore sarà 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 del codice di Script
non contiene stati osservabili JavaScript. La cache del codice può essere salvata in modo sicuro insieme alla sorgente dello script e utilizzata per costruire più volte nuove istanze di Script
.
Le funzioni nella sorgente Script
possono essere contrassegnate come compilate in modo pigro e non vengono compilate durante la costruzione di Script
. Queste funzioni verranno compilate quando vengono invocate per la prima volta. La cache del codice serializza i metadati che V8 conosce attualmente su 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
// all'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 è 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 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
.
Restituisce: <any> il risultato dell'ultima istruzione eseguita nello script.
Esegue il codice compilato contenuto dall'oggetto vm.Script
all'interno del contextifiedObject
dato e restituisce il risultato. L'esecuzione del codice non ha accesso all'ambito 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)
// Stampa: { animal: 'cat', count: 12, name: 'kitty' }
L'utilizzo delle opzioni timeout
o breakOnSigint
comporterà l'avvio di nuovi loop di eventi e thread corrispondenti, che hanno un sovraccarico 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
<Oggetto> | <vm.constants.DONT_CONTEXTIFY> | <undefined> Ovm.constants.DONT_CONTEXTIFY
oppure un oggetto che sarà contestualizzato. Seundefined
, un oggetto contestualizzato vuoto verrà creato per compatibilità con le versioni precedenti.options
<Oggetto>displayErrors
<booleano> Quandotrue
, se si verifica unErrore
durante la compilazione delcodice
, la riga di codice che causa l'errore è allegata alla traccia dello stack. Predefinito:true
.timeout
<intero> Specifica il numero di millisecondi per eseguirecodice
prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà generato unErrore
. Questo valore deve essere un intero strettamente positivo.breakOnSigint
<booleano> Setrue
, la ricezione diSIGINT
(+) terminerà l'esecuzione e genererà unErrore
. 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 dall'uomo del contesto appena creato. Predefinito:'VM Context i'
, dovei
è un indice numerico ascendente del contesto creato.contextOrigin
<stringa> Origine corrispondente al contesto appena creato per scopi di visualizzazione. L'origine dovrebbe essere formattata come un URL, ma solo con schema, host e porta (se necessario), come il valore della proprietàurl.origin
di un oggettoURL
. In particolare, questa stringa dovrebbe omettere la barra finale, poiché indica un percorso. Predefinito:''
.contextCodeGeneration
<Oggetto>strings
<booleano> Se impostato su false, qualsiasi chiamata aeval
o ai 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
.microtaskMode
<stringa> Se impostato suafterEvaluate
, i microtask (task pianificati tramitePromise
easync function
) verranno eseguiti immediatamente dopo l'esecuzione dello script. In tal caso, sono inclusi negli ambititimeout
ebreakOnSigint
.
Restituisce: <qualsiasi> il risultato dell'ultima istruzione eseguita nello script.
Questo metodo è una scorciatoia per script.runInContext(vm.createContext(options), options)
. Fa diverse cose 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 in ogni singolo contesto
.
const vm = require('node:vm')
const script = new vm.Script('globalVar = "set"')
const contexts = [{}, {}, {}]
contexts.forEach(context => {
script.runInNewContext(context)
})
console.log(contexts)
// Stampa: [{ globalVar: 'set' }, { globalVar: 'set' }, { globalVar: 'set' }]
// Questo genererebbe un'eccezione se il contesto è creato da un oggetto contestualizzato.
// vm.constants.DONT_CONTEXTIFY permette di creare 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 | Ora è supportata l'opzione breakOnSigint . |
v0.3.1 | Aggiunto in: v0.3.1 |
options
<Oggetto>displayErrors
<booleano> Se impostato sutrue
, se si verifica un erroreError
durante la compilazione del codice, la riga di codice che causa l'errore viene allegata alla traccia dello stack. Predefinito:true
.timeout
<intero> Specifica il numero di millisecondi per eseguire il codice prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà generato un erroreError
. Questo valore deve essere un intero strettamente positivo.breakOnSigint
<booleano> Se impostato sutrue
, la ricezione diSIGINT
(+) terminerà l'esecuzione e genererà un erroreError
. I gestori esistenti per l'evento che sono stati allegati tramiteprocess.on('SIGINT')
sono disabilitati durante l'esecuzione dello script, ma continuano a funzionare successivamente. Predefinito:false
.
Restituisce: <qualsiasi> 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.
Il seguente esempio compila il codice che incrementa una variabile global
, quindi esegue tale 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 è 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)
// Stampa: sourcemap.json
const vm = require('node:vm')
const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`)
console.log(script.sourceMapURL)
// Stampa: 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 di moduli ECMAScript in contesti VM. È la controparte della classe vm.Script
che rispecchia da vicino le registrazioni di moduli come definite nella specifica ECMAScript.
A differenza di vm.Script
, tuttavia, ogni oggetto vm.Module
è legato a un contesto dalla sua creazione. Le operazioni sugli oggetti vm.Module
sono intrinsecamente asincrone, al contrario della natura sincrona degli oggetti vm.Script
. L'utilizzo di funzioni 'async' può aiutare nella manipolazione degli oggetti vm.Module
.
L'utilizzo di un oggetto vm.Module
richiede tre passaggi distinti: creazione/analisi, collegamento e valutazione. Questi tre passaggi sono illustrati nell'esempio seguente.
Questa implementazione si trova a un livello inferiore rispetto al caricatore di moduli ECMAScript. Non c'è ancora modo di interagire con il caricatore, sebbene sia previsto il supporto.
import vm from 'node:vm'
const contextifiedObject = vm.createContext({
secret: 42,
print: console.log,
})
// Passo 1
//
// Crea un modulo costruendo un nuovo oggetto `vm.SourceTextModule`. Questo
// analizza il testo sorgente fornito, sollevando un `SyntaxError` se qualcosa va
// storto. Per impostazione predefinita, un modulo viene creato nel contesto superiore. Ma qui,
// specifichiamo `contextifiedObject` come contesto a cui appartiene questo modulo.
//
// Qui, tentiamo di ottenere l'esportazione predefinita dal modulo "foo" e
// di inserirla nel binding locale "secret".
const bar = new vm.SourceTextModule(
`
import s from 'foo';
s;
print(s);
`,
{ context: contextifiedObject }
)
// Passo 2
//
// "Collega" le dipendenze importate di questo modulo ad esso.
//
// La callback di collegamento fornita (il "linker") accetta due argomenti: il
// modulo padre (`bar` in questo caso) e la stringa che è lo specificatore del
// modulo importato. La 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, la stessa callback del linker
// verrà chiamata sul modulo restituito.
//
// Anche i moduli di livello superiore senza dipendenze devono essere collegati esplicitamente. La
// callback fornita non verrebbe mai chiamata, tuttavia.
//
// Il metodo link() restituisce una Promise che verrà risolta quando tutte le
// Promise restituite dal linker si risolvono.
//
// Nota: Questo è un esempio artificioso in quanto la funzione linker crea un nuovo
// modulo "foo" ogni volta che viene chiamata. In un sistema di moduli completo, una
// 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" durante la creazione del contesto.
export default secret;
`,
{ context: referencingModule.context }
)
// Usando `contextifiedObject` invece di `referencingModule.context`
// qui funzionerebbe altrettanto bene.
}
throw new Error(`Impossibile risolvere la dipendenza: ${specifier}`)
}
await bar.link(linker)
// Passo 3
//
// Valuta il modulo. Il metodo evaluate() restituisce una promise che si
// risolverà dopo che il modulo avrà terminato la valutazione.
// Stampa 42.
await bar.evaluate()
const vm = require('node:vm')
const contextifiedObject = vm.createContext({
secret: 42,
print: console.log,
})
;(async () => {
// Passo 1
//
// Crea un modulo costruendo un nuovo oggetto `vm.SourceTextModule`. Questo
// analizza il testo sorgente fornito, sollevando un `SyntaxError` se qualcosa va
// storto. Per impostazione predefinita, un modulo viene creato nel contesto superiore. Ma qui,
// specifichiamo `contextifiedObject` come contesto a cui appartiene questo modulo.
//
// Qui, tentiamo di ottenere l'esportazione predefinita dal modulo "foo" e
// di inserirla nel binding locale "secret".
const bar = new vm.SourceTextModule(
`
import s from 'foo';
s;
print(s);
`,
{ context: contextifiedObject }
)
// Passo 2
//
// "Collega" le dipendenze importate di questo modulo ad esso.
//
// La callback di collegamento fornita (il "linker") accetta due argomenti: il
// modulo padre (`bar` in questo caso) e la stringa che è lo specificatore del
// modulo importato. La 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, la stessa callback del linker
// verrà chiamata sul modulo restituito.
//
// Anche i moduli di livello superiore senza dipendenze devono essere collegati esplicitamente. La
// callback fornita non verrebbe mai chiamata, tuttavia.
//
// Il metodo link() restituisce una Promise che verrà risolta quando tutte le
// Promise restituite dal linker si risolvono.
//
// Nota: Questo è un esempio artificioso in quanto la funzione linker crea un nuovo
// modulo "foo" ogni volta che viene chiamata. In un sistema di moduli completo, una
// 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" durante la creazione del contesto.
export default secret;
`,
{ context: referencingModule.context }
)
// Usando `contextifiedObject` invece di `referencingModule.context`
// qui funzionerebbe altrettanto bene.
}
throw new Error(`Impossibile risolvere la dipendenza: ${specifier}`)
}
await bar.link(linker)
// Passo 3
//
// Valuta il modulo. Il metodo evaluate() restituisce una promise che si
// risolverà dopo che il modulo avrà terminato la valutazione.
// Stampa 42.
await bar.evaluate()
})()
module.dependencySpecifiers
Gli specificatori di tutte le dipendenze di questo modulo. La matrice restituita è bloccata per impedire qualsiasi modifica.
Corrisponde al campo [[RequestedModules]]
delle registrazioni dei moduli ciclici nella specifica ECMAScript.
module.error
Se lo module.status
è 'errored'
, questa proprietà contiene l'eccezione sollevata dal modulo durante la valutazione. Se lo stato è diverso, l'accesso a questa proprietà provocherà un'eccezione.
Il valore undefined
non può essere utilizzato per i casi in cui non vi è un'eccezione sollevata a causa di una possibile ambiguità con throw undefined;
.
Corrisponde al campo [[EvaluationError]]
delle registrazioni dei moduli ciclici nella specifica ECMAScript.
module.evaluate([options])
options
<Object>timeout
<integer> Specifica il numero di millisecondi da valutare prima di interrompere l'esecuzione. Se l'esecuzione viene interrotta, verrà sollevato unError
. Questo valore deve essere un intero strettamente positivo.breakOnSigint
<boolean> Setrue
, la ricezione diSIGINT
(+) interromperà l'esecuzione e solleverà 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. Default:false
.
Restituisce: <Promise> Risolve con
undefined
in caso di successo.
Valuta il modulo.
Questo deve essere chiamato dopo che il modulo è stato collegato; altrimenti verrà rifiutato. Può essere chiamato anche quando il modulo è già stato valutato, nel qual caso non farà nulla se la valutazione iniziale è terminata con successo (module.status
è 'evaluated'
) oppure rilancerà l'eccezione risultante dalla valutazione iniziale (module.status
è 'errored'
).
Questo metodo non può essere chiamato mentre il modulo sta venendo valutato (module.status
è 'evaluating'
).
Corrisponde al campo metodo concreto Evaluate() delle registrazioni dei moduli ciclici 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à retroattiva. |
linker
<Function>specifier
<string> Lo specificatore del modulo richiesto:referencingModule
<vm.Module> L'oggettoModule
su cui viene chiamatolink()
.extra
<Object>attributes
<Object> I dati dall'attributo: secondo ECMA-262, gli host devono generare 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 solo una volta per modulo.
La funzione dovrebbe restituire un oggetto Module
o una Promise
che alla fine si risolve 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, o 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 chiave:
- 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 secondo la specifica.
Corrisponde al campo del metodo concreto Link() delle registrazioni di moduli ciclici nella specifica ECMAScript.
module.namespace
L'oggetto namespace del modulo. Questo è disponibile solo dopo il completamento del collegamento (module.link()
).
Corrisponde all'operazione astratta GetModuleNamespace nella specifica ECMAScript.
module.status
Lo stato corrente del modulo. Sarà uno dei seguenti:
'unlinked'
:module.link()
non è ancora stato chiamato.'linking'
:module.link()
è stato chiamato, ma non tutte le Promise restituite dalla funzione di collegamento sono ancora state risolte.'linked'
: Il modulo è stato collegato correttamente e tutte le sue dipendenze sono collegate, mamodule.evaluate()
non è ancora stato chiamato.'evaluating'
: Il modulo sta per essere valutato tramitemodule.evaluate()
su se stesso o su un modulo padre.'evaluated'
: Il modulo è stato valutato correttamente.'errored'
: Il modulo è stato valutato, ma è stata sollevata un'eccezione.
A parte '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 diverso da 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.
- Estensioni: <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 supporto per gli attributi di importazione al parametro importModuleDynamically . |
code
<stringa> Codice del modulo JavaScript da analizzareoptions
identifier
<stringa> Stringa utilizzata nelle tracce dello stack. Predefinito:'vm:module(i)'
dovei
è un indice ascendente specifico del contesto.cachedData
<Buffer> | <TypedArray> | <DataView> Fornisce unBuffer
oTypedArray
, oDataView
opzionale con i dati della cache del codice di V8 per la sorgente fornita. Ilcode
deve essere lo stesso del modulo da cui è stato creato questocachedData
.context
<Oggetto> 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
<intero> Specifica l'offset del numero di riga visualizzato nelle tracce dello stack prodotte da questoModule
. Predefinito:0
.columnOffset
<intero> Specifica l'offset del numero di colonna della prima riga visualizzato nelle tracce dello stack prodotte da questoModule
. Predefinito:0
.initializeImportMeta
<Funzione> Chiamato durante la valutazione di questoModule
per inizializzareimport.meta
.meta
<import.meta>module
<vm.SourceTextModule>importModuleDynamically
<Funzione> 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. Non si consiglia di utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto diimport()
dinamico nelle API di compilazione.
Crea una nuova istanza 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) {
// Nota: questo oggetto è creato nel contesto superiore. Come tale,
// Object.getPrototypeOf(import.meta.prop) punta a
// Object.prototype nel contesto superiore piuttosto che in
// quello contestualizzato.
meta.prop = {}
},
})
// Poiché il modulo non ha dipendenze, la funzione di collegamento non verrà mai chiamata.
await module.link(() => {})
await module.evaluate()
// Ora, Object.prototype.secret sarà uguale a 42.
//
// Per risolvere questo problema, sostituire
// meta.prop = {};
// sopra con
// 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) {
// Nota: questo oggetto è creato nel contesto superiore. Come tale,
// Object.getPrototypeOf(import.meta.prop) punta a
// Object.prototype nel contesto superiore piuttosto che in
// quello contestualizzato.
meta.prop = {}
},
})
// Poiché il modulo non ha dipendenze, la funzione di collegamento non verrà mai chiamata.
await module.link(() => {})
await module.evaluate()
// Ora, Object.prototype.secret sarà uguale a 42.
//
// Per risolvere questo problema, sostituire
// meta.prop = {};
// sopra con
// 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 del SourceTextModule
non contiene stati osservabili JavaScript. La cache di codice può essere salvata in sicurezza insieme alla sorgente dello script e utilizzata per costruire più volte nuove istanze di SourceTextModule
.
Le funzioni nella sorgente SourceTextModule
possono essere contrassegnate come compilate in modo lazy e non vengono compilate durante la costruzione del SourceTextModule
. Queste funzioni verranno compilate quando vengono invocate per la prima volta. La cache di codice serializza i metadati che V8 conosce attualmente sul SourceTextModule
che può utilizzare per accelerare le compilazioni future.
// Crea un modulo iniziale
const module = new vm.SourceTextModule('const a = 1;')
// Crea dati in cache da questo modulo
const cachedData = module.createCachedData()
// Crea un nuovo modulo usando i dati in 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 Synthetic Module Record come definito nella specifica WebIDL. Lo scopo dei moduli sintetici è quello di 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)
})
// Usa `module` nel linking...
new vm.SyntheticModule(exportNames, evaluateCallback[, options])
Aggiunto in: v13.0.0, v12.16.0
exportNames
<string[]> Array di nomi che saranno esportati dal modulo.evaluateCallback
<Function> Chiamato quando il modulo viene valutato.options
identifier
<string> Stringa utilizzata nelle tracce dello stack. Default:'vm:module(i)'
dovei
è un indice ascendente specifico del contesto.context
<Object> L'oggetto contextified come restituito dal metodovm.createContext()
, per compilare e valutare questoModule
.
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 da impostare per l'esportazione.
Questo metodo viene utilizzato dopo che il modulo è stato 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 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 supporto per gli attributi di importazione al parametro importModuleDynamically . |
v15.9.0 | Opzione importModuleDynamically aggiunta nuovamente. |
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 | Aggiunta in: v10.10.0 |
code
<string> Il corpo della funzione da compilare.params
<string[]> Una matrice di stringhe contenente tutti i parametri per la funzione.options
<Object>filename
<string> Specifica il nome del file utilizzato nelle tracce dello stack prodotte da questo script. Default:''
.lineOffset
<number> Specifica l'offset del numero di riga visualizzato nelle tracce dello stack prodotte da questo script. Default:0
.columnOffset
<number> Specifica l'offset del numero di colonna della prima riga visualizzato nelle tracce dello stack prodotte da questo script. Default:0
.cachedData
<Buffer> | <TypedArray> | <DataView> Fornisce unBuffer
oTypedArray
, oDataView
opzionale con i dati della cache del codice di V8 per la sorgente fornita. Questo deve essere prodotto da una chiamata precedente avm.compileFunction()
con gli stessicode
eparams
.produceCachedData
<boolean> Specifica se produrre nuovi dati di cache. Default:false
.parsingContext
<Object> L'oggetto contestualizzato in cui la suddetta funzione dovrebbe essere compilata.contextExtensions
<Object[]> Una matrice contenente una raccolta di estensioni di contesto (oggetti che racchiudono lo scope corrente) da applicare durante la compilazione. Default:[]
.
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Usato per specificare come i moduli dovrebbero essere caricati durante la valutazione di questa funzione quando viene chiamatoimport()
. Questa opzione fa parte dell'API dei moduli sperimentali. Non si consiglia di utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto diimport()
dinamico nelle API di compilazione.Restituisce: <Function>
Compila il codice fornito nel contesto fornito (se non viene fornito alcun contesto, viene utilizzato il contesto corrente) e lo restituisce racchiuso in una funzione con i params
forniti.
vm.constants
Aggiunto in: v21.7.0, v20.12.0
Restituisce un oggetto contenente costanti comunemente utilizzate per le operazioni della 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 caricatore 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
che un oggetto che sarà contestualizzato. Seundefined
, verrà creato un oggetto contestualizzato vuoto per compatibilità con le versioni precedenti.options
<Object>name
<string> Nome leggibile dall'uomo del contesto appena creato. Predefinito:'VM Context i'
, dovei
è un indice numerico crescente del contesto creato.origin
<string> Origine corrispondente al contesto appena creato per scopi di visualizzazione. L'origine dovrebbe 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 il trattino di barra finale, in quanto indica un percorso. Predefinito:''
.codeGeneration
<Object>strings
<boolean> Se impostato su false, qualsiasi chiamata aeval
o ai costruttori di funzione (Function
,GeneratorFunction
, ecc.) genererà un erroreEvalError
. Predefinito:true
.wasm
<boolean> Se impostato su false, qualsiasi tentativo di compilare un modulo WebAssembly genererà un erroreWebAssembly.CompileError
. Predefinito:true
.microtaskMode
<string> Se impostato suafterEvaluate
, i microtask (task programmati tramitePromise
easync function
) verranno eseguiti immediatamente dopo che uno script è stato eseguito tramitescript.runInContext()
. In tal caso, sono inclusi negli ambititimeout
ebreakOnSigint
.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Utilizzato per specificare come i moduli dovrebbero essere caricati quandoimport()
viene chiamato in questo contesto senza uno script o un modulo di riferimento. Questa opzione fa parte dell'API dei moduli sperimentali. Non si consiglia di utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto diimport()
dinamico nelle API di compilazione.
Restituisce: <Object> oggetto contestualizzato.
Se il contextObject
fornito è 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 sarà racchiuso dal contextObject
, mantenendo tutte le sue proprietà esistenti ma avendo anche gli oggetti e le funzioni integrate di qualsiasi oggetto globale standard. 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, presenta alcune peculiarità rispetto agli oggetti globali ordinari. Ad esempio, non può essere congelato. Per creare un contesto senza le peculiarità della contestualizzazione, passare 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 tale contesto.
Il name
e l'origin
forniti del contesto sono resi visibili tramite l'API dell'ispettore.
vm.isContext(oggetto)
Aggiunto in: v0.11.7
oggetto
<Oggetto>- Restituisce: <booleano>
Restituisce true
se il dato oggetto oggetto
è stato contestualizzato usando vm.createContext()
, o se è l'oggetto globale di un contesto creato usando vm.constants.DONT_CONTEXTIFY
.
vm.measureMemory([opzioni])
Aggiunto in: v13.10.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1 - Sperimentale
Misura la memoria nota a V8 e utilizzata da tutti i contesti noti all'isolato V8 corrente, o dal contesto principale.
opzioni
<Oggetto> Opzionale.modalità
<stringa>'sommario'
o'dettagliato'
. In modalità sommario, verrà restituita solo la memoria misurata per il contesto principale. In modalità dettagliata, verrà restituita la memoria misurata per tutti i contesti noti all'isolato V8 corrente. Predefinito:'sommario'
esecuzione
<stringa>'predefinito'
o'immediata'
. Con l'esecuzione predefinita, la promise non si risolverà fino a dopo l'inizio della successiva raccolta dei rifiuti pianificata, il che potrebbe richiedere un po' di tempo (o mai se il programma termina prima della successiva GC). Con l'esecuzione immediata, la GC verrà avviata immediatamente per misurare la memoria. Predefinito:'predefinito'
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 ciascun spazio heap nell'istanza V8 corrente.
const vm = require('node:vm')
// Misura la memoria utilizzata dal contesto principale.
vm.measureMemory({ modalità: 'sommario' })
// Questo è lo stesso di vm.measureMemory()
.then(risultato => {
// Il formato corrente è:
// {
// totale: {
// stimaMemoriaJs: 2418479, intervalloMemoriaJs: [ 2418479, 2745799 ]
// }
// }
console.log(risultato)
})
const contesto = vm.createContext({ a: 1 })
vm.measureMemory({ modalità: 'dettagliato', esecuzione: 'immediata' }).then(risultato => {
// Fai riferimento al contesto qui in modo che non venga raccolto dalla GC
// fino al completamento della misurazione.
console.log(contesto.a)
// {
// totale: {
// stimaMemoriaJs: 2574732,
// intervalloMemoriaJs: [ 2574732, 2904372 ]
// },
// corrente: {
// stimaMemoriaJs: 2438996,
// intervalloMemoriaJs: [ 2438996, 2768636 ]
// },
// altro: [
// {
// stimaMemoriaJs: 135736,
// intervalloMemoriaJs: [ 135736, 465376 ]
// }
// ]
// }
console.log(risultato)
})
vm.runInContext(code, contextifiedObject[, options])
[Cronologia]
Versione | Modifiche |
---|---|
v21.7.0, v20.12.0 | Aggiunto supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Aggiunto 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.contextifiedObject
<Object> L'oggetto contestualizzato che verrà utilizzato comeglobal
quando ilcode
viene compilato ed eseguito.options
<Object> | <string>filename
<string> Specifica il nome del file utilizzato nelle tracce dello stack prodotte da questo script. Default:'evalmachine.\<anonymous\>'
.lineOffset
<number> Specifica l'offset del numero di riga visualizzato nelle tracce dello stack prodotte da questo script. Default:0
.columnOffset
<number> Specifica l'offset del numero di colonna della prima riga visualizzato nelle tracce dello stack prodotte da questo script. Default:0
.displayErrors
<boolean> Quandotrue
, se si verifica un erroreError
durante la compilazione delcode
, la riga di codice che causa l'errore è allegata alla traccia dello stack. Default:true
.timeout
<integer> Specifica il numero di millisecondi per eseguirecode
prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà generato un erroreError
. Questo valore deve essere un intero strettamente positivo.breakOnSigint
<boolean> Setrue
, la ricezione diSIGINT
(+) terminerà l'esecuzione e genererà un erroreError
. 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. Default:false
.cachedData
<Buffer> | <TypedArray> | <DataView> Fornisce unBuffer
oTypedArray
, oDataView
opzionale con i dati della cache del codice di V8 per la sorgente fornita.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Usato per specificare come i moduli dovrebbero essere caricati durante la valutazione di questo script quando viene chiamatoimport()
. Questa opzione fa parte dell'API dei moduli sperimentali. Non è consigliato 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 nel 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 usando il metodo vm.createContext()
.
Se options
è una stringa, specifica il nome del file.
Il seguente esempio compila ed esegue script diversi usando 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)
// Stampa: { 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 supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Aggiunto 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
<string> Il codice JavaScript da compilare ed eseguire.contextObject
<Object> | <vm.constants.DONT_CONTEXTIFY> | <undefined> Ovm.constants.DONT_CONTEXTIFY
o un oggetto che sarà contestualizzato. Seundefined
, verrà creato un oggetto contestualizzato vuoto per compatibilità con le versioni precedenti.filename
<string> Specifica il nome del file utilizzato nelle tracce dello stack prodotte da questo script. Default:'evalmachine.\<anonymous\>'
.lineOffset
<number> Specifica l'offset del numero di riga visualizzato nelle tracce dello stack prodotte da questo script. Default:0
.columnOffset
<number> Specifica l'offset del numero di colonna della prima riga visualizzato nelle tracce dello stack prodotte da questo script. Default:0
.displayErrors
<boolean> Quandotrue
, se si verifica un erroreError
durante la compilazione delcode
, la riga di codice che causa l'errore viene allegata alla traccia dello stack. Default:true
.timeout
<integer> Specifica il numero di millisecondi per eseguirecode
prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà generato un erroreError
. Questo valore deve essere un intero strettamente positivo.breakOnSigint
<boolean> Setrue
, la ricezione diSIGINT
(+) terminerà l'esecuzione e genererà un erroreError
. 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. Default:false
.contextName
<string> Nome leggibile dall'uomo del contesto appena creato. Default:'VM Context i'
, dovei
è un indice numerico crescente del contesto creato.contextOrigin
<string> Origine corrispondente al contesto appena creato per scopi di visualizzazione. L'origine dovrebbe essere formattata come un URL, ma solo con schema, host e porta (se necessario), come il valore della proprietàurl.origin
di un oggettoURL
. In particolare, questa stringa dovrebbe omettere il trattino di barra finale, in quanto indica un percorso. Default:''
.contextCodeGeneration
<Object>strings
<boolean> Se impostato su false, qualsiasi chiamata aeval
o a costruttori di funzioni (Function
,GeneratorFunction
, ecc.) genererà unEvalError
. Default:true
.wasm
<boolean> Se impostato su false, qualsiasi tentativo di compilare un modulo WebAssembly genererà unWebAssembly.CompileError
. Default:true
.cachedData
<Buffer> | <TypedArray> | <DataView> Fornisce unBuffer
oTypedArray
, oDataView
opzionale con i dati della cache del codice di V8 per la sorgente 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. Non si consiglia di utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto diimport()
dinamico nelle API di compilazione.microtaskMode
<string> Se impostato suafterEvaluate
, i microtask (task pianificati tramitePromise
easync function
) verranno eseguiti 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 il 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)
// Stampa: { animal: 'cat', count: 3, name: 'kitty' }
// Questo darebbe un errore se il contesto è creato da un oggetto contestualizzato.
// vm.constants.DONT_CONTEXTIFY permette di creare contesti con oggetti globali ordinari che
// possono essere congelati.
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 supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER . |
v17.0.0, v16.12.0 | Aggiunto 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 nelle tracce dello stack prodotte da questo script. Default:'evalmachine.\<anonymous\>'
.lineOffset
<number> Specifica l'offset del numero di riga visualizzato nelle tracce dello stack prodotte da questo script. Default:0
.columnOffset
<number> Specifica l'offset del numero di colonna della prima riga visualizzato nelle tracce dello stack prodotte da questo script. Default:0
.displayErrors
<boolean> Setrue
, se si verifica un erroreError
durante la compilazione delcode
, la riga di codice che causa l'errore viene allegata alla traccia dello stack. Default:true
.timeout
<integer> Specifica il numero di millisecondi per eseguirecode
prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà generato un erroreError
. Questo valore deve essere un intero strettamente positivo.breakOnSigint
<boolean> Setrue
, la ricezione diSIGINT
(+) terminerà l'esecuzione e genererà un erroreError
. 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. Default:false
.cachedData
<Buffer> | <TypedArray> | <DataView> Fornisce unBuffer
oTypedArray
, oDataView
opzionale con i dati della cache del codice di V8 per la sorgente fornita.importModuleDynamically
<Function> | <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. Non si consiglia di utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto diimport()
dinamico nelle API di compilazione.
Restituisce: <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 all'ambito locale, ma ha accesso all'oggetto global
corrente.
Se options
è una stringa, specifica il nome del file.
Il seguente esempio illustra l'utilizzo sia di vm.runInThisContext()
che della funzione JavaScript eval()
per eseguire lo stesso codice:
const vm = require('node:vm')
let localVar = 'valore iniziale'
const vmResult = vm.runInThisContext('localVar = "vm";')
console.log(`vmResult: '${vmResult}', localVar: '${localVar}'`)
// Stampa: vmResult: 'vm', localVar: 'valore iniziale'
const evalResult = eval('localVar = "eval";')
console.log(`evalResult: '${evalResult}', localVar: '${localVar}'`)
// Stampa: evalResult: 'eval', localVar: 'eval'
Poiché vm.runInThisContext()
non ha accesso all'ambito locale, localVar
non viene modificato. Al contrario, eval()
ha accesso all'ambito locale, quindi il valore localVar
viene modificato. In questo modo vm.runInThisContext()
è molto simile a una chiamata indiretta eval()
, ad esempio (0,eval)('code')
.
Esempio: Eseguire un server HTTP all'interno di una VM
Quando si utilizza [
script.runInThisContext()](/it/api/vm#scriptruninthiscontextoptions)
o [
vm.runInThisContext()](/it/api/vm#vmruninthiscontextcode-options)
, il codice viene eseguito all'interno del contesto globale V8 corrente. Il codice passato a questo contesto VM avrà il proprio ambito isolato.
Per eseguire un semplice server web utilizzando il modulo node:http
, il codice passato al contesto deve chiamare require('node:http')
autonomamente oppure deve 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 in esecuzione su http://127.0.0.1:8124/');
})`
vm.runInThisContext(code)(require)
In questo caso, require()
condivide lo stato con il contesto da cui viene passato. Questo può introdurre rischi quando viene eseguito codice non attendibile, ad esempio alterando gli oggetti nel contesto in modi indesiderati.
Cosa significa "contextificare" un oggetto?
Tutto il JavaScript eseguito all'interno di Node.js viene eseguito nell'ambito di un "contesto". Secondo la Guida per gli incorporatori 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
, un nuovo oggetto verrà creato dal contesto corrente prima della sua contextificazione). Questo contesto V8 fornisce al codice 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 della sua associazione con contextObject
nel contesto esterno è ciò che questo documento definisce "contextificazione" dell'oggetto.
La contextificazione introdurrebbe alcune peculiarità al valore globalThis
nel contesto. Ad esempio, non può essere congelato e non è referenzialmente uguale a contextObject
nel contesto esterno.
const vm = require('node:vm')
// Un'opzione `contextObject` indefinita rende contextificato l'oggetto globale.
const context = vm.createContext()
console.log(vm.runInContext('globalThis', context) === context) // false
// Un oggetto globale contextificato non può essere congelato.
try {
vm.runInContext('Object.freeze(globalThis);', context)
} catch (e) {
console.log(e) // TypeError: Impossibile congelare
}
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 peculiarità, specificare vm.constants.DONT_CONTEXTIFY
come argomento contextObject
.
vm.constants.DONT_CONTEXTIFY
Questa costante, quando utilizzata come argomento contextObject
nelle API vm, istruisce Node.js a creare un contesto senza avvolgere il suo oggetto globale con un altro oggetto in un modo specifico di Node.js. Di conseguenza, il valore globalThis
all'interno del nuovo contesto si comporterebbe più vicino a uno ordinario.
const vm = require('node:vm')
// Usa vm.constants.DONT_CONTEXTIFY per congelare 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 stranezze specifiche di Node.js. È uguale per riferimento al valore globalThis
nel nuovo contesto, può essere modificato dall'esterno del contesto e può essere utilizzato per accedere direttamente ai built-in nel nuovo contesto.
const vm = require('node:vm')
const context = vm.createContext(vm.constants.DONT_CONTEXTIFY)
// L'oggetto restituito è uguale per riferimento 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 congelato e questo 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 attività asincrone e Promise
Le Promise
e le async function
possono pianificare attività eseguite dal motore JavaScript in modo asincrono. Per impostazione predefinita, queste attività vengono eseguite dopo che tutte le funzioni JavaScript sullo stack corrente hanno terminato l'esecuzione. Ciò consente di evitare la 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 viene 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 del ritorno 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 delle Promise vengono inseriti nella coda dei microtask del contesto in cui sono stati creati. Ad esempio, se () =\> loop()
viene sostituito semplicemente con loop
nell'esempio precedente, allora loop
verrà inserito nella coda dei microtask globale, perché è una funzione del contesto esterno (principale), e quindi sarà anche in grado di evitare il timeout.
Se le funzioni di pianificazione asincrone come process.nextTick()
, queueMicrotask()
, setTimeout()
, setImmediate()
, ecc. vengono rese disponibili all'interno di un vm.Context
, le funzioni loro passate verranno aggiunte alle code globali, che sono condivise da tutti i contesti. Pertanto, i callback passati a tali funzioni non sono controllabili neanche tramite il timeout.
Supporto di import()
dinamico nelle API di compilazione
Le seguenti API supportano un'opzione importModuleDynamically
per abilitare l'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 e chiama effettivamente 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 viene avviato un import()
nel codice compilato, Node.js utilizzerà il caricatore ESM predefinito dal contesto principale per caricare il modulo richiesto e restituirlo al codice in esecuzione.
Questo fornisce 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 appartengono comunque al contesto principale e non sono instanceof
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 inoltre 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'
// Scrive test.js e test.txt nella directory in cui viene eseguito lo script corrente.
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')
// Scrive test.js e test.txt nella directory in cui viene eseguito lo script corrente.
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 sul caricamento di moduli utente utilizzando il caricatore predefinito dal contesto principale:
Quando importModuleDynamically
è una funzione
Quando importModuleDynamically
è una funzione, verrà invocata quando import()
viene chiamata nel codice compilato per consentire agli utenti di personalizzare il modo in cui 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, questa callback verrà ignorata. Se il codice valutato effettivamente chiama import()
, il risultato verrà rifiutato con ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAG
.
La callback importModuleDynamically(specifier, referrer, importAttributes)
ha la seguente segnatura:
specifier
<string> specificatore passato aimport()
referrer
<vm.Script> | <Function> | <vm.SourceTextModule> | <Object> Il referrer è lovm.Script
compilato pernew vm.Script
,vm.runInThisContext
,vm.runInContext
evm.runInNewContext
. È laFunction
compilata pervm.compileFunction
, lovm.SourceTextModule
compilato pernew vm.SourceTextModule
e il contestoObject
pervm.createContext()
.importAttributes
<Object> Il valore"with"
passato al parametro opzionaleoptionsExpression
, o un oggetto vuoto se nessun valore è stato fornito.- Restituisce: <Module Namespace Object> | <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' } }
})()