Skip to content

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.

js
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]

VersioneModifiche
v21.7.0, v20.12.0Aggiunto supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER.
v17.0.0, v16.12.0Aggiunto supporto per attributi di importazione al parametro importModuleDynamically.
v10.6.0produceCachedData è deprecato a favore di script.createCachedData().
v5.7.0Le opzioni cachedData e produceCachedData sono ora supportate.
v0.3.1Aggiunta 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 un Buffer o TypedArray, o DataView opzionale con i dati della cache del codice di V8 per la sorgente fornita. Quando fornito, il valore cachedDataRejected sarà impostato su true o false a seconda dell'accettazione dei dati da parte di V8.
    • produceCachedData <boolean> Quando true e non è presente cachedData, V8 tenterà di produrre dati della cache del codice per code. In caso di successo, verrà prodotto un Buffer con i dati della cache del codice di V8 e memorizzato nella proprietà cachedData dell'istanza vm.Script restituita. Il valore cachedDataProduced sarà impostato su true o false a seconda che i dati della cache del codice siano prodotti correttamente. Questa opzione è deprecata a favore di script.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 chiamato import(). Questa opzione fa parte dell'API dei moduli sperimentali. Si sconsiglia di utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto di import() 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

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.

js
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]

VersioneModifiche
v6.3.0L'opzione breakOnSigint è ora supportata.
v0.3.1Aggiunto in: v0.3.1
  • contextifiedObject <Object> Un oggetto contestualizzato come restituito dal metodo vm.createContext().

  • options <Object>

    • displayErrors <boolean> Quando true, se si verifica un Error durante la compilazione del code, la riga di codice che causa l'errore è allegata alla traccia dello stack. Predefinito: true.
    • timeout <integer> Specifica il numero di millisecondi per eseguire code prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà generato un Error. Questo valore deve essere un intero strettamente positivo.
    • breakOnSigint <boolean> Se true, la ricezione di SIGINT (+) terminerà l'esecuzione e genererà un Error. I gestori esistenti per l'evento che sono stati allegati tramite process.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.

js
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]

VersioneModifiche
v22.8.0, v20.18.0L'argomento contextObject ora accetta vm.constants.DONT_CONTEXTIFY.
v14.6.0L'opzione microtaskMode è ora supportata.
v10.0.0L'opzione contextCodeGeneration è ora supportata.
v6.3.0L'opzione breakOnSigint è ora supportata.
v0.3.1Aggiunto in: v0.3.1
  • contextObject <Oggetto> | <vm.constants.DONT_CONTEXTIFY> | <undefined> O vm.constants.DONT_CONTEXTIFY oppure un oggetto che sarà contestualizzato. Se undefined, un oggetto contestualizzato vuoto verrà creato per compatibilità con le versioni precedenti.

  • options <Oggetto>

    • displayErrors <booleano> Quando true, se si verifica un Errore durante la compilazione del codice, la riga di codice che causa l'errore è allegata alla traccia dello stack. Predefinito: true.

    • timeout <intero> Specifica il numero di millisecondi per eseguire codice prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà generato un Errore. Questo valore deve essere un intero strettamente positivo.

    • breakOnSigint <booleano> Se true, la ricezione di SIGINT (+) terminerà l'esecuzione e genererà un Errore. I gestori esistenti per l'evento che sono stati allegati tramite process.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', dove i è 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 oggetto URL. In particolare, questa stringa dovrebbe omettere la barra finale, poiché indica un percorso. Predefinito: ''.

    • contextCodeGeneration <Oggetto>

    • strings <booleano> Se impostato su false, qualsiasi chiamata a eval o ai costruttori di funzioni (Function, GeneratorFunction, ecc.) genererà un EvalError. Predefinito: true.

    • wasm <booleano> Se impostato su false, qualsiasi tentativo di compilare un modulo WebAssembly genererà un WebAssembly.CompileError. Predefinito: true.

    • microtaskMode <stringa> Se impostato su afterEvaluate, i microtask (task pianificati tramite Promise e async function) verranno eseguiti immediatamente dopo l'esecuzione dello script. In tal caso, sono inclusi negli ambiti timeout e breakOnSigint.

  • 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.

js
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]

VersioneModifiche
v6.3.0Ora è supportata l'opzione breakOnSigint.
v0.3.1Aggiunto in: v0.3.1
  • options <Oggetto>

    • displayErrors <booleano> Se impostato su true, se si verifica un errore Error 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 errore Error. Questo valore deve essere un intero strettamente positivo.
    • breakOnSigint <booleano> Se impostato su true, la ricezione di SIGINT (+) terminerà l'esecuzione e genererà un errore Error. I gestori esistenti per l'evento che sono stati allegati tramite process.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:

js
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.

js
import vm from 'node:vm'

const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`)

console.log(script.sourceMapURL)
// Stampa: sourcemap.json
js
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.

js
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()
js
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 un Error. Questo valore deve essere un intero strettamente positivo.
    • breakOnSigint <boolean> Se true, la ricezione di SIGINT (+) interromperà l'esecuzione e solleverà un Error. I gestori esistenti per l'evento che sono stati collegati tramite process.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]

VersioneModifiche
v21.1.0, v20.10.0, v18.19.0L'opzione extra.assert è rinominata in extra.attributes. Il nome precedente è ancora fornito per compatibilità retroattiva.

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:

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, ma module.evaluate() non è ancora stato chiamato.
  • 'evaluating': Il modulo sta per essere valutato tramite module.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.

La classe vm.SourceTextModule fornisce il Source Text Module Record come definito nella specifica ECMAScript.

new vm.SourceTextModule(code[, options])

[Cronologia]

VersioneModifiche
v17.0.0, v16.12.0Aggiunto supporto per gli attributi di importazione al parametro importModuleDynamically.
  • code <stringa> Codice del modulo JavaScript da analizzare

  • options

    • identifier <stringa> Stringa utilizzata nelle tracce dello stack. Predefinito: 'vm:module(i)' dove i è un indice ascendente specifico del contesto.

    • cachedData <Buffer> | <TypedArray> | <DataView> Fornisce un Buffer o TypedArray, o DataView opzionale con i dati della cache del codice di V8 per la sorgente fornita. Il code deve essere lo stesso del modulo da cui è stato creato questo cachedData.

    • context <Oggetto> L'oggetto contestualizzato come restituito dal metodo vm.createContext(), per compilare e valutare questo Module 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 questo Module. Predefinito: 0.

    • columnOffset <intero> Specifica l'offset del numero di colonna della prima riga visualizzato nelle tracce dello stack prodotte da questo Module. Predefinito: 0.

    • initializeImportMeta <Funzione> Chiamato durante la valutazione di questo Module per inizializzare import.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 chiamato import(). Questa opzione fa parte dell'API dei moduli sperimentali. Non si consiglia di utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto di import() 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.

js
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);
js
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

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.

js
// 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.

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.

js
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)' dove i è un indice ascendente specifico del contesto.
    • context <Object> L'oggetto contextified come restituito dal metodo vm.createContext(), per compilare e valutare questo Module.

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.

js
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)
js
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]

VersioneModifiche
v21.7.0, v20.12.0Aggiunto supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER.
v19.6.0, v18.15.0Il valore restituito ora include cachedDataRejected con la stessa semantica della versione vm.Script se è stata passata l'opzione cachedData.
v17.0.0, v16.12.0Aggiunto supporto per gli attributi di importazione al parametro importModuleDynamically.
v15.9.0Opzione importModuleDynamically aggiunta nuovamente.
v14.3.0Rimozione di importModuleDynamically a causa di problemi di compatibilità.
v14.1.0, v13.14.0L'opzione importModuleDynamically è ora supportata.
v10.10.0Aggiunta 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 un Buffer o TypedArray, o DataView opzionale con i dati della cache del codice di V8 per la sorgente fornita. Questo deve essere prodotto da una chiamata precedente a vm.compileFunction() con gli stessi code e params.
    • 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 chiamato import(). Questa opzione fa parte dell'API dei moduli sperimentali. Non si consiglia di utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto di import() 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]

VersioneModifiche
v22.8.0, v20.18.0L'argomento contextObject ora accetta vm.constants.DONT_CONTEXTIFY.
v21.7.0, v20.12.0Aggiunto il supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER.
v21.2.0, v20.11.0L'opzione importModuleDynamically è ora supportata.
v14.6.0L'opzione microtaskMode è ora supportata.
v10.0.0Il primo argomento non può più essere una funzione.
v10.0.0L'opzione codeGeneration è ora supportata.
v0.3.1Aggiunto in: v0.3.1
  • contextObject <Object> | <vm.constants.DONT_CONTEXTIFY> | <undefined> Sia vm.constants.DONT_CONTEXTIFY che un oggetto che sarà contestualizzato. Se undefined, 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', dove i è 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 oggetto URL. 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 a eval o ai costruttori di funzione (Function, GeneratorFunction, ecc.) genererà un errore EvalError. Predefinito: true.

    • wasm <boolean> Se impostato su false, qualsiasi tentativo di compilare un modulo WebAssembly genererà un errore WebAssembly.CompileError. Predefinito: true.

    • microtaskMode <string> Se impostato su afterEvaluate, i microtask (task programmati tramite Promise e async function) verranno eseguiti immediatamente dopo che uno script è stato eseguito tramite script.runInContext(). In tal caso, sono inclusi negli ambiti timeout e breakOnSigint.

    • importModuleDynamically <Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Utilizzato per specificare come i moduli dovrebbero essere caricati quando import() 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 di import() 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.

js
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

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.

js
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]

VersioneModifiche
v21.7.0, v20.12.0Aggiunto supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER.
v17.0.0, v16.12.0Aggiunto supporto per gli attributi di importazione al parametro importModuleDynamically.
v6.3.0L'opzione breakOnSigint è ora supportata.
v0.3.1Aggiunto in: v0.3.1
  • code <string> Il codice JavaScript da compilare ed eseguire.
  • contextifiedObject <Object> L'oggetto contestualizzato che verrà utilizzato come global quando il code 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> Quando true, se si verifica un errore Error durante la compilazione del code, la riga di codice che causa l'errore è allegata alla traccia dello stack. Default: true.
    • timeout <integer> Specifica il numero di millisecondi per eseguire code prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà generato un errore Error. Questo valore deve essere un intero strettamente positivo.
    • breakOnSigint <boolean> Se true, la ricezione di SIGINT (+) terminerà l'esecuzione e genererà un errore Error. I gestori esistenti per l'evento che sono stati allegati tramite process.on('SIGINT') sono disabilitati durante l'esecuzione dello script, ma continuano a funzionare dopo. Default: false.
    • cachedData <Buffer> | <TypedArray> | <DataView> Fornisce un Buffer o TypedArray, o DataView 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 chiamato import(). Questa opzione fa parte dell'API dei moduli sperimentali. Non è consigliato utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto di import() 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:

js
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]

VersioneModifiche
v22.8.0, v20.18.0L'argomento contextObject ora accetta vm.constants.DONT_CONTEXTIFY.
v21.7.0, v20.12.0Aggiunto supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER.
v17.0.0, v16.12.0Aggiunto supporto per gli attributi di importazione al parametro importModuleDynamically.
v14.6.0L'opzione microtaskMode è ora supportata.
v10.0.0L'opzione contextCodeGeneration è ora supportata.
v6.3.0L'opzione breakOnSigint è ora supportata.
v0.3.1Aggiunto in: v0.3.1
  • code <string> Il codice JavaScript da compilare ed eseguire.

  • contextObject <Object> | <vm.constants.DONT_CONTEXTIFY> | <undefined> O vm.constants.DONT_CONTEXTIFY o un oggetto che sarà contestualizzato. Se undefined, verrà creato un oggetto contestualizzato vuoto per compatibilità con le versioni precedenti.

  • 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> Quando true, se si verifica un errore Error durante la compilazione del code, la riga di codice che causa l'errore viene allegata alla traccia dello stack. Default: true.

    • timeout <integer> Specifica il numero di millisecondi per eseguire code prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà generato un errore Error. Questo valore deve essere un intero strettamente positivo.

    • breakOnSigint <boolean> Se true, la ricezione di SIGINT (+) terminerà l'esecuzione e genererà un errore Error. I gestori esistenti per l'evento che sono stati allegati tramite process.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', dove i è 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 oggetto URL. 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 a eval o a costruttori di funzioni (Function, GeneratorFunction, ecc.) genererà un EvalError. Default: true.

    • wasm <boolean> Se impostato su false, qualsiasi tentativo di compilare un modulo WebAssembly genererà un WebAssembly.CompileError. Default: true.

    • cachedData <Buffer> | <TypedArray> | <DataView> Fornisce un Buffer o TypedArray, o DataView 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 chiamato import(). Questa opzione fa parte dell'API dei moduli sperimentali. Non si consiglia di utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto di import() dinamico nelle API di compilazione.

    • microtaskMode <string> Se impostato su afterEvaluate, i microtask (task pianificati tramite Promise e async function) verranno eseguiti immediatamente dopo l'esecuzione dello script. In tal caso, sono inclusi negli ambiti timeout e breakOnSigint.

  • 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.

js
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]

VersioneModifiche
v21.7.0, v20.12.0Aggiunto supporto per vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER.
v17.0.0, v16.12.0Aggiunto supporto per gli attributi di importazione al parametro importModuleDynamically.
v6.3.0L'opzione breakOnSigint è ora supportata.
v0.3.1Aggiunto in: v0.3.1
  • code <string> Il codice JavaScript da compilare ed eseguire.

  • 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> Se true, se si verifica un errore Error durante la compilazione del code, la riga di codice che causa l'errore viene allegata alla traccia dello stack. Default: true.
    • timeout <integer> Specifica il numero di millisecondi per eseguire code prima di terminare l'esecuzione. Se l'esecuzione viene terminata, verrà generato un errore Error. Questo valore deve essere un intero strettamente positivo.
    • breakOnSigint <boolean> Se true, la ricezione di SIGINT (+) terminerà l'esecuzione e genererà un errore Error. I gestori esistenti per l'evento che sono stati allegati tramite process.on('SIGINT') sono disabilitati durante l'esecuzione dello script, ma continuano a funzionare dopo. Default: false.
    • cachedData <Buffer> | <TypedArray> | <DataView> Fornisce un Buffer o TypedArray, o DataView 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 chiamato import(). Questa opzione fa parte dell'API dei moduli sperimentali. Non si consiglia di utilizzarla in un ambiente di produzione. Per informazioni dettagliate, vedere Supporto di import() 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:

js
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:

js
'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.

js
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.

js
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.

js
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:

js
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:

js
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.

js
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)
js
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:

js
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)
js
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 a import()
  • referrer <vm.Script> | <Function> | <vm.SourceTextModule> | <Object> Il referrer è lo vm.Script compilato per new vm.Script, vm.runInThisContext, vm.runInContext e vm.runInNewContext. È la Function compilata per vm.compileFunction, lo vm.SourceTextModule compilato per new vm.SourceTextModule e il contesto Object per vm.createContext().
  • importAttributes <Object> Il valore "with" passato al parametro opzionale optionsExpression, 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 funzioni then.
js
// 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' } }
js
// 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' } }
})()