- assert 断言
- async_hooks 异步钩子
- async_hooks/context 异步上下文
- buffer 缓冲区
- C++插件
- C/C++插件(使用 Node-API)
- C++嵌入器
- child_process 子进程
- cluster 集群
- CLI 命令行
- console 控制台
- Corepack 核心包
- crypto 加密
- crypto/webcrypto 网络加密
- debugger 调试器
- deprecation 弃用
- dgram 数据报
- diagnostics_channel 诊断通道
- dns 域名服务器
- domain 域
- Error 错误
- events 事件触发器
- fs 文件系统
- global 全局变量
- http 超文本传输协议
- http2 超文本传输协议 2.0
- https 安全超文本传输协议
- inspector 检查器
- Intl 国际化
- module 模块
- module/cjs CommonJS 模块
- module/esm ECMAScript 模块
- module/package 包模块
- module/typescript TS 模块
- net 网络
- os 操作系统
- path 路径
- perf_hooks 性能钩子
- permission 权限
- process 进程
- punycode 域名代码
- querystring 查询字符串
- readline 逐行读取
- repl 交互式解释器
- report 诊断报告
- sea 单个可执行应用程序
Node.js v22.12.0 文档
- Node.js v22.12.0
-
目录
- 虚拟机(执行 JavaScript)
- 类:
vm.Script
- 类:
vm.Module
- 类:
vm.SourceTextModule
- 类:
vm.SyntheticModule
vm.compileFunction(code[, params[, options]])
vm.constants
vm.createContext([contextObject[, options]])
vm.isContext(object)
vm.measureMemory([options])
vm.runInContext(code, contextifiedObject[, options])
vm.runInNewContext(code[, contextObject[, options]])
vm.runInThisContext(code[, options])
- 示例:在虚拟机中运行 HTTP 服务器
- "contextify" 一个对象是什么意思?
- 与异步任务和 Promises 的超时交互
- 编译 API 中支持动态
import()
- 类:
- 虚拟机(执行 JavaScript)
-
导航
- assert 断言
- async_hooks 异步钩子
- async_hooks/context 异步上下文
- buffer 缓冲区
- C++插件
- C/C++插件(使用 Node-API)
- C++嵌入器
- child_process 子进程
- cluster 集群
- CLI 命令行
- console 控制台
- Corepack 核心包
- crypto 加密
- crypto/webcrypto 网络加密
- debugger 调试器
- deprecation 弃用
- dgram 数据报
- diagnostics_channel 诊断通道
- dns 域名服务器
- domain 域
- Error 错误
- events 事件触发器
- fs 文件系统
- global 全局变量
- http 超文本传输协议
- http2 超文本传输协议 2.0
- https 安全超文本传输协议
- inspector 检查器
- Intl 国际化
- module 模块
- module/cjs CommonJS 模块
- module/esm ECMAScript 模块
- module/package 包模块
- module/typescript TS 模块
- net 网络
- os 操作系统
- path 路径
- perf_hooks 性能钩子
- permission 权限
- process 进程
- punycode 域名代码
- querystring 查询字符串
- readline 逐行读取
- repl 交互式解释器
- report 诊断报告
- sea 单个可执行应用程序
- 其他版本
虚拟机(执行 JavaScript)#
¥VM (executing JavaScript)
¥Stability: 2 - Stable
源代码: lib/vm.js
node:vm
模块允许在 V8 虚拟机上下文中编译和运行代码。
¥The node:vm
module enables compiling and running code within V8 Virtual
Machine contexts.
node:vm
模块不是安全机制。不要用它来运行不受信任的代码。
¥The node:vm
module is not a security
mechanism. Do not use it to run untrusted code.
JavaScript 代码可以立即编译并运行,也可以编译、保存并稍后运行。
¥JavaScript code can be compiled and run immediately or compiled, saved, and run later.
常见的用例是在不同的 V8 上下文中运行代码。这意味着被调用的代码与调用代码具有不同的全局对象。
¥A common use case is to run the code in a different V8 Context. This means invoked code has a different global object than the invoking code.
可以通过 contextifying 对象提供上下文。调用的代码将上下文中的任何属性视为全局变量。由调用的代码引起的对全局变量的任何更改都反映在上下文对象中。
¥One can provide the context by contextifying an object. The invoked code treats any property in the context like a global variable. Any changes to global variables caused by the invoked code are reflected in the context object.
const vm = require('node:vm');
const x = 1;
const context = { x: 2 };
vm.createContext(context); // Contextify the object.
const code = 'x += 40; var y = 17;';
// `x` and `y` are global variables in the context.
// Initially, x has the value 2 because that is the value of context.x.
vm.runInContext(code, context);
console.log(context.x); // 42
console.log(context.y); // 17
console.log(x); // 1; y is not defined.
类:vm.Script
#
¥Class: vm.Script
vm.Script
类的实例包含可以在特定上下文中执行的预编译脚本。
¥Instances of the vm.Script
class contain precompiled scripts that can be
executed in specific contexts.
new vm.Script(code[, options])
#
-
code
<string> 要编译的 JavaScript 代码。¥
code
<string> The JavaScript code to compile. -
-
filename
<string> 指定此脚本生成的堆栈跟踪中使用的文件名。默认值:'evalmachine.<anonymous>'
。¥
filename
<string> Specifies the filename used in stack traces produced by this script. Default:'evalmachine.<anonymous>'
. -
lineOffset
<number> 指定在此脚本生成的堆栈跟踪中显示的行号偏移量。默认值:0
。¥
lineOffset
<number> Specifies the line number offset that is displayed in stack traces produced by this script. Default:0
. -
columnOffset
<number> 指定在此脚本生成的堆栈跟踪中显示的第一行列号偏移量。默认值:0
。¥
columnOffset
<number> Specifies the first-line column number offset that is displayed in stack traces produced by this script. Default:0
. -
cachedData
<Buffer> | <TypedArray> | <DataView> 为所提供的源提供可选的Buffer
或TypedArray
或DataView
,其中包含 V8 的代码缓存数据。当提供时,cachedDataRejected
值将设置为true
或false
,具体取决于 V8 对数据的接受程度。¥
cachedData
<Buffer> | <TypedArray> | <DataView> Provides an optionalBuffer
orTypedArray
, orDataView
with V8's code cache data for the supplied source. When supplied, thecachedDataRejected
value will be set to eithertrue
orfalse
depending on acceptance of the data by V8. -
produceCachedData
<boolean> 当true
且没有cachedData
存在时,则 V8 将尝试为code
生成代码缓存数据。当成功后,会生成带有 V8 代码缓存数据的Buffer
并存储在返回的vm.Script
实例的cachedData
属性中。cachedDataProduced
值将设置为true
或false
,这取决于代码缓存数据是否成功生成。此选项已弃用,取而代之的是script.createCachedData()
。默认值:false
。¥
produceCachedData
<boolean> Whentrue
and nocachedData
is present, V8 will attempt to produce code cache data forcode
. Upon success, aBuffer
with V8's code cache data will be produced and stored in thecachedData
property of the returnedvm.Script
instance. ThecachedDataProduced
value will be set to eithertrue
orfalse
depending on whether code cache data is produced successfully. This option is deprecated in favor ofscript.createCachedData()
. Default:false
. -
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> 用于指定在调用import()
时评估此脚本期间应如何加载模块。此选项是实验模块 API 的一部分。不建议在生产环境中使用它。详细信息参见 编译 API 中支持动态import()
。¥
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Used to specify how the modules should be loaded during the evaluation of this script whenimport()
is called. This option is part of the experimental modules API. We do not recommend using it in a production environment. For detailed information, see Support of dynamicimport()
in compilation APIs.
-
如果 options
是字符串,则指定文件名。
¥If options
is a string, then it specifies the filename.
创建新的 vm.Script
对象编译 code
但不运行它。编译后的 vm.Script
可以多次运行。code
没有绑定到任何全局对象;相反,它在每次运行之前绑定,仅针对该运行。
¥Creating a new vm.Script
object compiles code
but does not run it. The
compiled vm.Script
can be run later multiple times. The code
is not bound to
any global object; rather, it is bound before each run, just for that run.
script.cachedDataRejected
#
当提供 cachedData
来创建 vm.Script
时,该值将根据 V8 对数据的接受情况设置为 true
或 false
。否则值为 undefined
。
¥When cachedData
is supplied to create the vm.Script
, this value will be set
to either true
or false
depending on acceptance of the data by V8.
Otherwise the value is undefined
.
script.createCachedData()
#
创建可与 Script
构造函数的 cachedData
选项一起使用的代码缓存。返回 Buffer
。此方法可以随时调用任意次数。
¥Creates a code cache that can be used with the Script
constructor's
cachedData
option. Returns a Buffer
. This method may be called at any
time and any number of times.
Script
的代码缓存不包含任何 JavaScript 可观察状态。代码缓存可以安全地与脚本源一起保存,并用于多次构造新的 Script
实例。
¥The code cache of the Script
doesn't contain any JavaScript observable
states. The code cache is safe to be saved along side the script source and
used to construct new Script
instances multiple times.
Script
源代码中的函数可以标记为延迟编译,并且在构建 Script
时不会编译它们。这些函数将在第一次调用时被编译。代码缓存序列化 V8 目前知道的关于 Script
的元数据,它可以用来加速未来的编译。
¥Functions in the Script
source can be marked as lazily compiled and they are
not compiled at construction of the Script
. These functions are going to be
compiled when they are invoked the first time. The code cache serializes the
metadata that V8 currently knows about the Script
that it can use to speed up
future compilations.
const script = new vm.Script(`
function add(a, b) {
return a + b;
}
const x = add(1, 2);
`);
const cacheWithoutAdd = script.createCachedData();
// In `cacheWithoutAdd` the function `add()` is marked for full compilation
// upon invocation.
script.runInThisContext();
const cacheWithAdd = script.createCachedData();
// `cacheWithAdd` contains fully compiled function `add()`.
script.runInContext(contextifiedObject[, options])
#
-
contextifiedObject
<Object>vm.createContext()
方法返回的 contextified 对象。¥
contextifiedObject
<Object> A contextified object as returned by thevm.createContext()
method. -
options
<Object>-
displayErrors
<boolean> 当为true
时,如果编译code
时出现Error
,则导致错误的代码行会附加到堆栈跟踪中。默认值:true
。¥
displayErrors
<boolean> Whentrue
, if anError
occurs while compiling thecode
, the line of code causing the error is attached to the stack trace. Default:true
. -
timeout
<integer> 指定终止执行前执行code
的毫秒数。如果执行终止,则将抛出Error
。此值必须是严格的正整数。¥
timeout
<integer> Specifies the number of milliseconds to executecode
before terminating execution. If execution is terminated, anError
will be thrown. This value must be a strictly positive integer. -
breakOnSigint
<boolean> 如果是true
,接收SIGINT
(Ctrl+C)将终止执行并抛出Error
。已通过process.on('SIGINT')
附加的事件的现有句柄在脚本执行期间被禁用,但在此之后继续工作。默认值:false
。¥
breakOnSigint
<boolean> Iftrue
, receivingSIGINT
(Ctrl+C) will terminate execution and throw anError
. Existing handlers for the event that have been attached viaprocess.on('SIGINT')
are disabled during script execution, but continue to work after that. Default:false
.
-
-
返回:<any> 脚本中最后一条语句执行的结果。
¥Returns: <any> the result of the very last statement executed in the script.
在给定的 contextifiedObject
中运行 vm.Script
对象包含的编译代码并返回结果。运行代码无权访问本地作用域。
¥Runs the compiled code contained by the vm.Script
object within the given
contextifiedObject
and returns the result. Running code does not have access
to local scope.
下面的示例编译代码,增加一个全局变量,设置另一个全局变量的值,然后多次执行代码。全局变量包含在 context
对象中。
¥The following example compiles code that increments a global variable, sets
the value of another global variable, then execute the code multiple times.
The globals are contained in the context
object.
const vm = require('node:vm');
const context = {
animal: 'cat',
count: 2,
};
const script = new vm.Script('count += 1; name = "kitty";');
vm.createContext(context);
for (let i = 0; i < 10; ++i) {
script.runInContext(context);
}
console.log(context);
// Prints: { animal: 'cat', count: 12, name: 'kitty' }
使用 timeout
或 breakOnSigint
选项将导致新的事件循环和相应的线程被启动,其性能开销非零。
¥Using the timeout
or breakOnSigint
options will result in new event loops
and corresponding threads being started, which have a non-zero performance
overhead.
script.runInNewContext([contextObject[, options]])
#
-
contextObject
<Object> | <undefined>vm.constants.DONT_CONTEXTIFY
或将成为 contextified 的对象。如果是undefined
,将创建一个空的上下文化对象以实现向后兼容。¥
contextObject
<Object> | <undefined> Eithervm.constants.DONT_CONTEXTIFY
or an object that will be contextified. Ifundefined
, an empty contextified object will be created for backwards compatibility. -
options
<Object>-
displayErrors
<boolean> 当为true
时,如果编译code
时出现Error
,则导致错误的代码行会附加到堆栈跟踪中。默认值:true
。¥
displayErrors
<boolean> Whentrue
, if anError
occurs while compiling thecode
, the line of code causing the error is attached to the stack trace. Default:true
. -
timeout
<integer> 指定终止执行前执行code
的毫秒数。如果执行终止,则将抛出Error
。此值必须是严格的正整数。¥
timeout
<integer> Specifies the number of milliseconds to executecode
before terminating execution. If execution is terminated, anError
will be thrown. This value must be a strictly positive integer. -
breakOnSigint
<boolean> 如果是true
,接收SIGINT
(Ctrl+C)将终止执行并抛出Error
。已通过process.on('SIGINT')
附加的事件的现有句柄在脚本执行期间被禁用,但在此之后继续工作。默认值:false
。¥
breakOnSigint
<boolean> Iftrue
, receivingSIGINT
(Ctrl+C) will terminate execution and throw anError
. Existing handlers for the event that have been attached viaprocess.on('SIGINT')
are disabled during script execution, but continue to work after that. Default:false
. -
contextName
<string> 新创建的上下文的可读名称。默认值:'VM Context i'
,其中i
是所创建上下文的升序数字索引。¥
contextName
<string> Human-readable name of the newly created context. Default:'VM Context i'
, wherei
is an ascending numerical index of the created context. -
contextOrigin
<string> 起源 对应于新创建的上下文,用于显示目的。来源的格式应该像 URL,但只有协议、主机和端口(如果需要),就像URL
对象的url.origin
属性的值。最值得注意的是,该字符串应省略尾部斜杠,因为它表示路径。默认值:''
。¥
contextOrigin
<string> Origin corresponding to the newly created context for display purposes. The origin should be formatted like a URL, but with only the scheme, host, and port (if necessary), like the value of theurl.origin
property of aURL
object. Most notably, this string should omit the trailing slash, as that denotes a path. Default:''
. -
contextCodeGeneration
<Object>-
strings
<boolean> 如果设置为 false,则任何对eval
或函数构造函数(Function
、GeneratorFunction
等)的调用都将抛出EvalError
。默认值:true
。¥
strings
<boolean> If set to false any calls toeval
or function constructors (Function
,GeneratorFunction
, etc) will throw anEvalError
. Default:true
. -
wasm
<boolean> 如果设置为 false,则任何编译 WebAssembly 模块的尝试都将抛出WebAssembly.CompileError
。默认值:true
。¥
wasm
<boolean> If set to false any attempt to compile a WebAssembly module will throw aWebAssembly.CompileError
. Default:true
.
-
-
microtaskMode
<string> 如果设置为afterEvaluate
,微任务(通过Promise
和async function
安排的任务)将在脚本运行后立即运行。在这种情况下,它们包含在timeout
和breakOnSigint
范围内。¥
microtaskMode
<string> If set toafterEvaluate
, microtasks (tasks scheduled throughPromise
s andasync function
s) will be run immediately after the script has run. They are included in thetimeout
andbreakOnSigint
scopes in that case.
-
-
返回:<any> 脚本中最后一条语句执行的结果。
¥Returns: <any> the result of the very last statement executed in the script.
此方法是 script.runInContext(vm.createContext(options), options)
的快捷方式。它同时做几件事:
¥This method is a shortcut to script.runInContext(vm.createContext(options), options)
.
It does several things at once:
-
创建一个新的上下文。
¥Creates a new context.
-
如果
contextObject
是一个对象,则使用新上下文对其进行 contextifies 操作。如果contextObject
未定义,则创建一个新对象并对其进行 contextifies 操作。如果contextObject
是vm.constants.DONT_CONTEXTIFY
,则不要 contextify 任何内容。¥If
contextObject
is an object, contextifies it with the new context. IfcontextObject
is undefined, creates a new object and contextifies it. IfcontextObject
isvm.constants.DONT_CONTEXTIFY
, don't contextify anything. -
在创建的上下文中运行
vm.Script
对象包含的编译代码。代码无权访问调用此方法的范围。¥Runs the compiled code contained by the
vm.Script
object within the created context. The code does not have access to the scope in which this method is called. -
返回结果。
¥Returns the result.
以下示例编译设置全局变量的代码,然后在不同的上下文中多次执行代码。全局变量设置并包含在每个单独的 context
中。
¥The following example compiles code that sets a global variable, then executes
the code multiple times in different contexts. The globals are set on and
contained within each individual context
.
const vm = require('node:vm');
const script = new vm.Script('globalVar = "set"');
const contexts = [{}, {}, {}];
contexts.forEach((context) => {
script.runInNewContext(context);
});
console.log(contexts);
// Prints: [{ globalVar: 'set' }, { globalVar: 'set' }, { globalVar: 'set' }]
// This would throw if the context is created from a contextified object.
// vm.constants.DONT_CONTEXTIFY allows creating contexts with ordinary
// global objects that can be frozen.
const freezeScript = new vm.Script('Object.freeze(globalThis); globalThis;');
const frozenContext = freezeScript.runInNewContext(vm.constants.DONT_CONTEXTIFY);
script.runInThisContext([options])
#
-
options
<Object>-
displayErrors
<boolean> 当为true
时,如果编译code
时出现Error
,则导致错误的代码行会附加到堆栈跟踪中。默认值:true
。¥
displayErrors
<boolean> Whentrue
, if anError
occurs while compiling thecode
, the line of code causing the error is attached to the stack trace. Default:true
. -
timeout
<integer> 指定终止执行前执行code
的毫秒数。如果执行终止,则将抛出Error
。此值必须是严格的正整数。¥
timeout
<integer> Specifies the number of milliseconds to executecode
before terminating execution. If execution is terminated, anError
will be thrown. This value must be a strictly positive integer. -
breakOnSigint
<boolean> 如果是true
,接收SIGINT
(Ctrl+C)将终止执行并抛出Error
。已通过process.on('SIGINT')
附加的事件的现有句柄在脚本执行期间被禁用,但在此之后继续工作。默认值:false
。¥
breakOnSigint
<boolean> Iftrue
, receivingSIGINT
(Ctrl+C) will terminate execution and throw anError
. Existing handlers for the event that have been attached viaprocess.on('SIGINT')
are disabled during script execution, but continue to work after that. Default:false
.
-
-
返回:<any> 脚本中最后一条语句执行的结果。
¥Returns: <any> the result of the very last statement executed in the script.
在当前 global
对象的上下文中运行 vm.Script
包含的编译代码。运行代码无权访问局部作用域,但可以访问当前 global
对象。
¥Runs the compiled code contained by the vm.Script
within the context of the
current global
object. Running code does not have access to local scope, but
does have access to the current global
object.
下面的示例编译了增加 global
变量的代码,然后多次执行该代码:
¥The following example compiles code that increments a global
variable then
executes that code multiple times:
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
#
当脚本从包含源映射魔术注释的源编译时,此属性将设置为源映射的 URL。
¥When the script is compiled from a source that contains a source map magic comment, this property will be set to the URL of the source map.
import vm from 'node:vm';
const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`);
console.log(script.sourceMapURL);
// Prints: sourcemap.json
const vm = require('node:vm');
const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`);
console.log(script.sourceMapURL);
// Prints: sourcemap.json
类:vm.Module
#
¥Class: vm.Module
¥Stability: 1 - Experimental
此特性仅在启用 --experimental-vm-modules
命令标志时可用。
¥This feature is only available with the --experimental-vm-modules
command
flag enabled.
vm.Module
类为在 VM 上下文中使用 ECMAScript 模块提供了低层接口。它是 vm.Script
类的对应物,密切反映了 ECMAScript 规范中定义的 模块记录。
¥The vm.Module
class provides a low-level interface for using
ECMAScript modules in VM contexts. It is the counterpart of the vm.Script
class that closely mirrors Module Records as defined in the ECMAScript
specification.
但是,与 vm.Script
不同,每个 vm.Module
对象都从它的创建开始绑定到上下文。与 vm.Script
对象的同步性质相比,对 vm.Module
对象的操作本质上是异步的。使用 'async' 函数可以帮助操作 vm.Module
对象。
¥Unlike vm.Script
however, every vm.Module
object is bound to a context from
its creation. Operations on vm.Module
objects are intrinsically asynchronous,
in contrast with the synchronous nature of vm.Script
objects. The use of
'async' functions can help with manipulating vm.Module
objects.
使用 vm.Module
对象需要三个不同的步骤:创建/解析、链接和评估。以下示例说明了这三个步骤
¥Using a vm.Module
object requires three distinct steps: creation/parsing,
linking, and evaluation. These three steps are illustrated in the following
example.
此实现位于比 ECMAScript 模块加载器 更低的级别。虽然计划提供支持,但也无法与加载器交互。
¥This implementation lies at a lower level than the ECMAScript Module loader. There is also no way to interact with the Loader yet, though support is planned.
import vm from 'node:vm';
const contextifiedObject = vm.createContext({
secret: 42,
print: console.log,
});
// Step 1
//
// Create a Module by constructing a new `vm.SourceTextModule` object. This
// parses the provided source text, throwing a `SyntaxError` if anything goes
// wrong. By default, a Module is created in the top context. But here, we
// specify `contextifiedObject` as the context this Module belongs to.
//
// Here, we attempt to obtain the default export from the module "foo", and
// put it into local binding "secret".
const bar = new vm.SourceTextModule(`
import s from 'foo';
s;
print(s);
`, { context: contextifiedObject });
// Step 2
//
// "Link" the imported dependencies of this Module to it.
//
// The provided linking callback (the "linker") accepts two arguments: the
// parent module (`bar` in this case) and the string that is the specifier of
// the imported module. The callback is expected to return a Module that
// corresponds to the provided specifier, with certain requirements documented
// in `module.link()`.
//
// If linking has not started for the returned Module, the same linker
// callback will be called on the returned Module.
//
// Even top-level Modules without dependencies must be explicitly linked. The
// callback provided would never be called, however.
//
// The link() method returns a Promise that will be resolved when all the
// Promises returned by the linker resolve.
//
// Note: This is a contrived example in that the linker function creates a new
// "foo" module every time it is called. In a full-fledged module system, a
// cache would probably be used to avoid duplicated modules.
async function linker(specifier, referencingModule) {
if (specifier === 'foo') {
return new vm.SourceTextModule(`
// The "secret" variable refers to the global variable we added to
// "contextifiedObject" when creating the context.
export default secret;
`, { context: referencingModule.context });
// Using `contextifiedObject` instead of `referencingModule.context`
// here would work as well.
}
throw new Error(`Unable to resolve dependency: ${specifier}`);
}
await bar.link(linker);
// Step 3
//
// Evaluate the Module. The evaluate() method returns a promise which will
// resolve after the module has finished evaluating.
// Prints 42.
await bar.evaluate();
const vm = require('node:vm');
const contextifiedObject = vm.createContext({
secret: 42,
print: console.log,
});
(async () => {
// Step 1
//
// Create a Module by constructing a new `vm.SourceTextModule` object. This
// parses the provided source text, throwing a `SyntaxError` if anything goes
// wrong. By default, a Module is created in the top context. But here, we
// specify `contextifiedObject` as the context this Module belongs to.
//
// Here, we attempt to obtain the default export from the module "foo", and
// put it into local binding "secret".
const bar = new vm.SourceTextModule(`
import s from 'foo';
s;
print(s);
`, { context: contextifiedObject });
// Step 2
//
// "Link" the imported dependencies of this Module to it.
//
// The provided linking callback (the "linker") accepts two arguments: the
// parent module (`bar` in this case) and the string that is the specifier of
// the imported module. The callback is expected to return a Module that
// corresponds to the provided specifier, with certain requirements documented
// in `module.link()`.
//
// If linking has not started for the returned Module, the same linker
// callback will be called on the returned Module.
//
// Even top-level Modules without dependencies must be explicitly linked. The
// callback provided would never be called, however.
//
// The link() method returns a Promise that will be resolved when all the
// Promises returned by the linker resolve.
//
// Note: This is a contrived example in that the linker function creates a new
// "foo" module every time it is called. In a full-fledged module system, a
// cache would probably be used to avoid duplicated modules.
async function linker(specifier, referencingModule) {
if (specifier === 'foo') {
return new vm.SourceTextModule(`
// The "secret" variable refers to the global variable we added to
// "contextifiedObject" when creating the context.
export default secret;
`, { context: referencingModule.context });
// Using `contextifiedObject` instead of `referencingModule.context`
// here would work as well.
}
throw new Error(`Unable to resolve dependency: ${specifier}`);
}
await bar.link(linker);
// Step 3
//
// Evaluate the Module. The evaluate() method returns a promise which will
// resolve after the module has finished evaluating.
// Prints 42.
await bar.evaluate();
})();
module.dependencySpecifiers
#
该模块所有依赖的说明符。返回的数组被冻结,不允许对其进行任何更改。
¥The specifiers of all dependencies of this module. The returned array is frozen to disallow any changes to it.
对应 ECMAScript 规范中 循环模块记录 的 [[RequestedModules]]
字段。
¥Corresponds to the [[RequestedModules]]
field of Cyclic Module Records in
the ECMAScript specification.
module.error
#
如果 module.status
为 'errored'
,则该属性包含模块在求值过程中抛出的异常。如果状态是别的,访问这个属性会导致抛出异常。
¥If the module.status
is 'errored'
, this property contains the exception
thrown by the module during evaluation. If the status is anything else,
accessing this property will result in a thrown exception.
值 undefined
不能用于由于可能与 throw undefined;
有歧义而没有抛出异常的情况。
¥The value undefined
cannot be used for cases where there is not a thrown
exception due to possible ambiguity with throw undefined;
.
对应 ECMAScript 规范中 循环模块记录 的 [[EvaluationError]]
字段。
¥Corresponds to the [[EvaluationError]]
field of Cyclic Module Records
in the ECMAScript specification.
module.evaluate([options])
#
-
options
<Object>-
timeout
<integer> 指定终止执行前要评估的毫秒数。如果执行中断,则会抛出Error
。此值必须是严格的正整数。¥
timeout
<integer> Specifies the number of milliseconds to evaluate before terminating execution. If execution is interrupted, anError
will be thrown. This value must be a strictly positive integer. -
breakOnSigint
<boolean> 如果是true
,接收SIGINT
(Ctrl+C)将终止执行并抛出Error
。已通过process.on('SIGINT')
附加的事件的现有句柄在脚本执行期间被禁用,但在此之后继续工作。默认值:false
。¥
breakOnSigint
<boolean> Iftrue
, receivingSIGINT
(Ctrl+C) will terminate execution and throw anError
. Existing handlers for the event that have been attached viaprocess.on('SIGINT')
are disabled during script execution, but continue to work after that. Default:false
.
-
-
返回:<Promise> 成功时将使用
undefined
履行。¥Returns: <Promise> Fulfills with
undefined
upon success.
评估模块。
¥Evaluate the module.
这必须在模块链接后调用;否则它会拒绝。当模块已经被评估时,它也可以被调用,在这种情况下,如果初始评估成功结束(module.status
是 'evaluated'
),则它将不做任何事情,或者它会重新抛出初始评估导致的异常(module.status
是 'errored'
)。
¥This must be called after the module has been linked; otherwise it will reject.
It could be called also when the module has already been evaluated, in which
case it will either do nothing if the initial evaluation ended in success
(module.status
is 'evaluated'
) or it will re-throw the exception that the
initial evaluation resulted in (module.status
is 'errored'
).
在评估模块时无法调用此方法(module.status
为 'evaluating'
)。
¥This method cannot be called while the module is being evaluated
(module.status
is 'evaluating'
).
对应 ECMAScript 规范中 循环模块记录 的 Evaluate() 具体方法 字段。
¥Corresponds to the Evaluate() concrete method field of Cyclic Module Records in the ECMAScript specification.
module.identifier
#
当前模块的标识符,在构造函数中设置。
¥The identifier of the current module, as set in the constructor.
module.link(linker)
#
-
linker
<Function>-
specifier
<string> 请求模块的说明符:¥
specifier
<string> The specifier of the requested module:import foo from 'foo'; // ^^^^^ the module specifier
-
referencingModule
<vm.Module>Module
对象link()
被调用。¥
referencingModule
<vm.Module> TheModule
objectlink()
is called on. -
extra
<Object>-
attributes
<Object> 来自属性的数据:¥
attributes
<Object> The data from the attribute:import foo from 'foo' with { name: 'value' }; // ^^^^^^^^^^^^^^^^^ the attribute
根据 ECMA-262,如果存在不受支持的属性,主机预计会触发错误。
¥Per ECMA-262, hosts are expected to trigger an error if an unsupported attribute is present.
-
assert
<Object>extra.attributes
的别名。¥
assert
<Object> Alias forextra.attributes
.
-
-
返回:<vm.Module> | <Promise>
¥Returns: <vm.Module> | <Promise>
-
-
返回:<Promise>
¥Returns: <Promise>
链接模块依赖。此方法必须在求值前调用,并且每个模块只能调用一次。
¥Link module dependencies. This method must be called before evaluation, and can only be called once per module.
该函数应返回 Module
对象或最终解析为 Module
对象的 Promise
。返回的 Module
必须满足以下两个不变量:
¥The function is expected to return a Module
object or a Promise
that
eventually resolves to a Module
object. The returned Module
must satisfy the
following two invariants:
-
它必须与父
Module
属于相同的上下文。¥It must belong to the same context as the parent
Module
. -
它的
status
不能是'errored'
。¥Its
status
must not be'errored'
.
如果返回的 Module
的 status
是 'unlinked'
,则将在返回的 Module
上递归调用此方法,并使用相同提供的 linker
函数。
¥If the returned Module
's status
is 'unlinked'
, this method will be
recursively called on the returned Module
with the same provided linker
function.
link()
返回 Promise
,当所有链接实例都解析为有效的 Module
时,它将被解析,或者如果链接器函数抛出异常或返回无效的 Module
,则被拒绝。
¥link()
returns a Promise
that will either get resolved when all linking
instances resolve to a valid Module
, or rejected if the linker function either
throws an exception or returns an invalid Module
.
链接器函数大致对应于 ECMAScript 规范中实现定义的 HostResolveImportedModule 抽象操作,但有几个关键区别:
¥The linker function roughly corresponds to the implementation-defined HostResolveImportedModule abstract operation in the ECMAScript specification, with a few key differences:
-
链接器函数允许异步,而 HostResolveImportedModule 是同步的。
¥The linker function is allowed to be asynchronous while HostResolveImportedModule is synchronous.
模块链接期间使用的实际 HostResolveImportedModule 实现是返回链接期间链接的模块的实现。由于此时所有模块都已经完全链接,因此 HostResolveImportedModule 实现根据规范是完全同步的。
¥The actual HostResolveImportedModule implementation used during module linking is one that returns the modules linked during linking. Since at that point all modules would have been fully linked already, the HostResolveImportedModule implementation is fully synchronous per specification.
对应 ECMAScript 规范中 循环模块记录 的 Link() 具体方法 字段。
¥Corresponds to the Link() concrete method field of Cyclic Module Records in the ECMAScript specification.
module.namespace
#
模块的命名空间对象。这仅在链接 (module.link()
) 完成后可用。
¥The namespace object of the module. This is only available after linking
(module.link()
) has completed.
对应 ECMAScript 规范中的 GetModuleNamespace 抽象操作。
¥Corresponds to the GetModuleNamespace abstract operation in the ECMAScript specification.
module.status
#
模块的当前状态。将是以下之一:
¥The current status of the module. Will be one of:
-
'unlinked'
:module.link()
还没有被调用。¥
'unlinked'
:module.link()
has not yet been called. -
'linking'
:module.link()
已被调用,但链接器函数返回的 Promise 尚未全部解决。¥
'linking'
:module.link()
has been called, but not all Promises returned by the linker function have been resolved yet. -
'linked'
:模块已成功链接,其所有依赖都已链接,但尚未调用module.evaluate()
。¥
'linked'
: The module has been linked successfully, and all of its dependencies are linked, butmodule.evaluate()
has not yet been called. -
'evaluating'
:该模块正在通过自身或父模块上的module.evaluate()
进行评估。¥
'evaluating'
: The module is being evaluated through amodule.evaluate()
on itself or a parent module. -
'evaluated'
:模块已成功评估。¥
'evaluated'
: The module has been successfully evaluated. -
'errored'
:模块已被评估,但抛出异常。¥
'errored'
: The module has been evaluated, but an exception was thrown.
除了 'errored'
,此状态字符串对应于规范的 循环模块记录 的 [[Status]]
字段。'errored'
对应于规范中的 'evaluated'
,但 [[EvaluationError]]
设置为不是 undefined
的值。
¥Other than 'errored'
, this status string corresponds to the specification's
Cyclic Module Record's [[Status]]
field. 'errored'
corresponds to
'evaluated'
in the specification, but with [[EvaluationError]]
set to a
value that is not undefined
.
类:vm.SourceTextModule
#
¥Class: vm.SourceTextModule
¥Stability: 1 - Experimental
此特性仅在启用 --experimental-vm-modules
命令标志时可用。
¥This feature is only available with the --experimental-vm-modules
command
flag enabled.
-
继承:<vm.Module>
¥Extends: <vm.Module>
vm.SourceTextModule
类提供 ECMAScript 规范中定义的 源文本模块记录。
¥The vm.SourceTextModule
class provides the Source Text Module Record as
defined in the ECMAScript specification.
new vm.SourceTextModule(code[, options])
#
-
code
<string> 要解析的 JavaScript 模块代码¥
code
<string> JavaScript Module code to parse -
options
-
identifier
<string> 用于堆栈跟踪的字符串。默认值:'vm:module(i)'
,其中i
是上下文特定的升序索引。¥
identifier
<string> String used in stack traces. Default:'vm:module(i)'
wherei
is a context-specific ascending index. -
cachedData
<Buffer> | <TypedArray> | <DataView> 为所提供的源提供可选的Buffer
或TypedArray
或DataView
,其中包含 V8 的代码缓存数据。code
必须与创建此cachedData
的模块相同。¥
cachedData
<Buffer> | <TypedArray> | <DataView> Provides an optionalBuffer
orTypedArray
, orDataView
with V8's code cache data for the supplied source. Thecode
must be the same as the module from which thiscachedData
was created. -
context
<Object>vm.createContext()
方法返回的 contextified 对象,用于编译和评估此Module
中的对象。如果未指定上下文,则在当前执行上下文中评估模块。¥
context
<Object> The contextified object as returned by thevm.createContext()
method, to compile and evaluate thisModule
in. If no context is specified, the module is evaluated in the current execution context. -
lineOffset
<integer> 指定在此Module
产生的堆栈跟踪中显示的行号偏移量。默认值:0
。¥
lineOffset
<integer> Specifies the line number offset that is displayed in stack traces produced by thisModule
. Default:0
. -
columnOffset
<integer> 指定在此Module
生成的堆栈跟踪中显示的第一行列号偏移量。默认值:0
。¥
columnOffset
<integer> Specifies the first-line column number offset that is displayed in stack traces produced by thisModule
. Default:0
. -
initializeImportMeta
<Function> 在评估此Module
期间调用以初始化import.meta
。¥
initializeImportMeta
<Function> Called during evaluation of thisModule
to initialize theimport.meta
.-
meta
<import.meta> -
module
<vm.SourceTextModule>
-
-
importModuleDynamically
<Function> 用于指定在调用import()
时评估该模块期间应如何加载模块。此选项是实验模块 API 的一部分。不建议在生产环境中使用它。详细信息参见 编译 API 中支持动态import()
。¥
importModuleDynamically
<Function> Used to specify the how the modules should be loaded during the evaluation of this module whenimport()
is called. This option is part of the experimental modules API. We do not recommend using it in a production environment. For detailed information, see Support of dynamicimport()
in compilation APIs.
-
创建新的 SourceTextModule
实例。
¥Creates a new SourceTextModule
instance.
分配给作为对象的 import.meta
对象的属性可能允许模块访问指定 context
之外的信息。使用 vm.runInContext()
在特定上下文中创建对象。
¥Properties assigned to the import.meta
object that are objects may
allow the module to access information outside the specified context
. Use
vm.runInContext()
to create objects in a specific context.
import vm from 'node:vm';
const contextifiedObject = vm.createContext({ secret: 42 });
const module = new vm.SourceTextModule(
'Object.getPrototypeOf(import.meta.prop).secret = secret;',
{
initializeImportMeta(meta) {
// Note: this object is created in the top context. As such,
// Object.getPrototypeOf(import.meta.prop) points to the
// Object.prototype in the top context rather than that in
// the contextified object.
meta.prop = {};
},
});
// Since module has no dependencies, the linker function will never be called.
await module.link(() => {});
await module.evaluate();
// Now, Object.prototype.secret will be equal to 42.
//
// To fix this problem, replace
// meta.prop = {};
// above with
// meta.prop = vm.runInContext('{}', contextifiedObject);
const vm = require('node:vm');
const contextifiedObject = vm.createContext({ secret: 42 });
(async () => {
const module = new vm.SourceTextModule(
'Object.getPrototypeOf(import.meta.prop).secret = secret;',
{
initializeImportMeta(meta) {
// Note: this object is created in the top context. As such,
// Object.getPrototypeOf(import.meta.prop) points to the
// Object.prototype in the top context rather than that in
// the contextified object.
meta.prop = {};
},
});
// Since module has no dependencies, the linker function will never be called.
await module.link(() => {});
await module.evaluate();
// Now, Object.prototype.secret will be equal to 42.
//
// To fix this problem, replace
// meta.prop = {};
// above with
// meta.prop = vm.runInContext('{}', contextifiedObject);
})();
sourceTextModule.createCachedData()
#
创建可与 SourceTextModule
构造函数的 cachedData
选项一起使用的代码缓存。返回 Buffer
。在评估模块之前,可以多次调用此方法。
¥Creates a code cache that can be used with the SourceTextModule
constructor's
cachedData
option. Returns a Buffer
. This method may be called any number
of times before the module has been evaluated.
SourceTextModule
的代码缓存不包含任何 JavaScript 可观察状态。代码缓存可以安全地与脚本源一起保存,并用于多次构造新的 SourceTextModule
实例。
¥The code cache of the SourceTextModule
doesn't contain any JavaScript
observable states. The code cache is safe to be saved along side the script
source and used to construct new SourceTextModule
instances multiple times.
SourceTextModule
源代码中的函数可以标记为延迟编译,并且在构建 SourceTextModule
时不会编译它们。这些函数将在第一次调用时被编译。代码缓存序列化 V8 目前知道的关于 SourceTextModule
的元数据,它可以用来加速未来的编译。
¥Functions in the SourceTextModule
source can be marked as lazily compiled
and they are not compiled at construction of the SourceTextModule
. These
functions are going to be compiled when they are invoked the first time. The
code cache serializes the metadata that V8 currently knows about the
SourceTextModule
that it can use to speed up future compilations.
// Create an initial module
const module = new vm.SourceTextModule('const a = 1;');
// Create cached data from this module
const cachedData = module.createCachedData();
// Create a new module using the cached data. The code must be the same.
const module2 = new vm.SourceTextModule('const a = 1;', { cachedData });
类:vm.SyntheticModule
#
¥Class: vm.SyntheticModule
¥Stability: 1 - Experimental
此特性仅在启用 --experimental-vm-modules
命令标志时可用。
¥This feature is only available with the --experimental-vm-modules
command
flag enabled.
-
继承:<vm.Module>
¥Extends: <vm.Module>
vm.SyntheticModule
类提供了 WebIDL 规范中定义的 合成模块记录。合成模块的目的是提供通用的接口,用于将非 JavaScript 源暴露给 ECMAScript 模块图。
¥The vm.SyntheticModule
class provides the Synthetic Module Record as
defined in the WebIDL specification. The purpose of synthetic modules is to
provide a generic interface for exposing non-JavaScript sources to ECMAScript
module graphs.
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);
});
// Use `module` in linking...
new vm.SyntheticModule(exportNames, evaluateCallback[, options])
#
-
exportNames
<string[]> 将从模块导出的名称数组。¥
exportNames
<string[]> Array of names that will be exported from the module. -
evaluateCallback
<Function> 在评估模块时调用。¥
evaluateCallback
<Function> Called when the module is evaluated. -
options
-
identifier
<string> 用于堆栈跟踪的字符串。默认值:'vm:module(i)'
,其中i
是上下文特定的升序索引。¥
identifier
<string> String used in stack traces. Default:'vm:module(i)'
wherei
is a context-specific ascending index. -
context
<Object>vm.createContext()
方法返回的 contextified 对象,用于编译和评估此Module
中的对象。¥
context
<Object> The contextified object as returned by thevm.createContext()
method, to compile and evaluate thisModule
in.
-
创建新的 SyntheticModule
实例。
¥Creates a new SyntheticModule
instance.
分配给此实例导出的对象可能允许模块的导入者访问指定 context
之外的信息。使用 vm.runInContext()
在特定上下文中创建对象。
¥Objects assigned to the exports of this instance may allow importers of
the module to access information outside the specified context
. Use
vm.runInContext()
to create objects in a specific context.
syntheticModule.setExport(name, value)
#
-
name
<string> 要设置的导出名称。¥
name
<string> Name of the export to set. -
value
<any> 将导出设置为的值。¥
value
<any> The value to set the export to.
此方法用于模块链接后设置导出的值。如果在链接模块之前调用,则会抛出 ERR_VM_MODULE_STATUS
错误。
¥This method is used after the module is linked to set the values of exports. If
it is called before the module is linked, an ERR_VM_MODULE_STATUS
error
will be thrown.
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]])
#
-
code
<string> 要编译的函数体。¥
code
<string> The body of the function to compile. -
params
<string[]> 包含函数所有参数的字符串数组。¥
params
<string[]> An array of strings containing all parameters for the function. -
options
<Object>-
filename
<string> 指定此脚本生成的堆栈跟踪中使用的文件名。默认值:''
。¥
filename
<string> Specifies the filename used in stack traces produced by this script. Default:''
. -
lineOffset
<number> 指定在此脚本生成的堆栈跟踪中显示的行号偏移量。默认值:0
。¥
lineOffset
<number> Specifies the line number offset that is displayed in stack traces produced by this script. Default:0
. -
columnOffset
<number> 指定在此脚本生成的堆栈跟踪中显示的第一行列号偏移量。默认值:0
。¥
columnOffset
<number> Specifies the first-line column number offset that is displayed in stack traces produced by this script. Default:0
. -
cachedData
<Buffer> | <TypedArray> | <DataView> 为所提供的源提供可选的Buffer
或TypedArray
或DataView
,其中包含 V8 的代码缓存数据。这必须通过使用相同的code
和params
预先调用vm.compileFunction()
来生成。¥
cachedData
<Buffer> | <TypedArray> | <DataView> Provides an optionalBuffer
orTypedArray
, orDataView
with V8's code cache data for the supplied source. This must be produced by a prior call tovm.compileFunction()
with the samecode
andparams
. -
produceCachedData
<boolean> 指定是否产生新的缓存数据。默认值:false
。¥
produceCachedData
<boolean> Specifies whether to produce new cache data. Default:false
. -
parsingContext
<Object> 应在其中编译所述函数的 contextified 对象。¥
parsingContext
<Object> The contextified object in which the said function should be compiled in. -
contextExtensions
<Object[]> 包含要在编译时应用的上下文扩展集合(包含当前作用域的对象)的数组。默认值:[]
。¥
contextExtensions
<Object[]> An array containing a collection of context extensions (objects wrapping the current scope) to be applied while compiling. Default:[]
.
-
-
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> 用于指定在调用import()
时评估此函数期间应如何加载模块。此选项是实验模块 API 的一部分。不建议在生产环境中使用它。详细信息参见 编译 API 中支持动态import()
。¥
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Used to specify the how the modules should be loaded during the evaluation of this function whenimport()
is called. This option is part of the experimental modules API. We do not recommend using it in a production environment. For detailed information, see Support of dynamicimport()
in compilation APIs. -
返回:<Function>
¥Returns: <Function>
将给定的代码编译到提供的上下文中(如果没有提供上下文,则使用当前上下文),并返回它封装在具有给定 params
的函数中。
¥Compiles the given code into the provided context (if no context is
supplied, the current context is used), and returns it wrapped inside a
function with the given params
.
vm.constants
#
返回一个包含 VM 操作常用常量的对象。
¥Returns an object containing commonly used constants for VM operations.
vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER
#
¥Stability: 1.1 - Active development
一个常量,可用作 vm.Script
和 vm.compileFunction()
的 importModuleDynamically
选项,以便 Node.js 使用主上下文中的默认 ESM 加载器来加载请求的模块。
¥A constant that can be used as the importModuleDynamically
option to
vm.Script
and vm.compileFunction()
so that Node.js uses the default
ESM loader from the main context to load the requested module.
详细信息参见 编译 API 中支持动态 import()
。
¥For detailed information, see
Support of dynamic import()
in compilation APIs.
vm.createContext([contextObject[, options]])
#
-
contextObject
<Object> | <undefined>vm.constants.DONT_CONTEXTIFY
或将成为 contextified 的对象。如果是undefined
,将创建一个空的上下文化对象以实现向后兼容。¥
contextObject
<Object> | <undefined> Eithervm.constants.DONT_CONTEXTIFY
or an object that will be contextified. Ifundefined
, an empty contextified object will be created for backwards compatibility. -
options
<Object>-
name
<string> 新创建的上下文的可读名称。默认值:'VM Context i'
,其中i
是所创建上下文的升序数字索引。¥
name
<string> Human-readable name of the newly created context. Default:'VM Context i'
, wherei
is an ascending numerical index of the created context. -
origin
<string> 起源 对应于新创建的上下文,用于显示目的。来源的格式应该像 URL,但只有协议、主机和端口(如果需要),就像URL
对象的url.origin
属性的值。最值得注意的是,该字符串应省略尾部斜杠,因为它表示路径。默认值:''
。¥
origin
<string> Origin corresponding to the newly created context for display purposes. The origin should be formatted like a URL, but with only the scheme, host, and port (if necessary), like the value of theurl.origin
property of aURL
object. Most notably, this string should omit the trailing slash, as that denotes a path. Default:''
. -
codeGeneration
<Object>-
strings
<boolean> 如果设置为 false,则任何对eval
或函数构造函数(Function
、GeneratorFunction
等)的调用都将抛出EvalError
。默认值:true
。¥
strings
<boolean> If set to false any calls toeval
or function constructors (Function
,GeneratorFunction
, etc) will throw anEvalError
. Default:true
. -
wasm
<boolean> 如果设置为 false,则任何编译 WebAssembly 模块的尝试都将抛出WebAssembly.CompileError
。默认值:true
。¥
wasm
<boolean> If set to false any attempt to compile a WebAssembly module will throw aWebAssembly.CompileError
. Default:true
.
-
-
microtaskMode
<string> 如果设置为afterEvaluate
,微任务(通过Promise
和async function
安排的任务)将在脚本运行通过script.runInContext()
后立即运行。在这种情况下,它们包含在timeout
和breakOnSigint
范围内。¥
microtaskMode
<string> If set toafterEvaluate
, microtasks (tasks scheduled throughPromise
s andasync function
s) will be run immediately after a script has run throughscript.runInContext()
. They are included in thetimeout
andbreakOnSigint
scopes in that case. -
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> 用于指定在没有引用脚本或模块的情况下在此上下文中调用import()
时应如何加载模块。此选项是实验模块 API 的一部分。不建议在生产环境中使用它。详细信息参见 编译 API 中支持动态import()
。¥
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Used to specify the how the modules should be loaded whenimport()
is called in this context without a referrer script or module. This option is part of the experimental modules API. We do not recommend using it in a production environment. For detailed information, see Support of dynamicimport()
in compilation APIs.
-
-
返回:<Object> 上下文对象。
¥Returns: <Object> contextified object.
如果给定的 contextObject
是一个对象,则 vm.createContext()
方法将 准备那个对象 并返回对它的引用,以便可以在对 vm.runInContext()
或 script.runInContext()
的调用中使用它。在这样的脚本中,全局对象将被 contextObject
封装,保留其所有现有属性,但也具有任何标准 全局对象 所具有的内置对象和函数。在 vm 模块运行的脚本之外,全局变量将保持不变。
¥If the given contextObject
is an object, the vm.createContext()
method will prepare that
object and return a reference to it so that it can be used in
calls to vm.runInContext()
or script.runInContext()
. Inside such
scripts, the global object will be wrapped by the contextObject
, retaining all of its
existing properties but also having the built-in objects and functions any
standard global object has. Outside of scripts run by the vm module, global
variables will remain unchanged.
const vm = require('node:vm');
global.globalVar = 3;
const context = { globalVar: 1 };
vm.createContext(context);
vm.runInContext('globalVar *= 2;', context);
console.log(context);
// Prints: { globalVar: 2 }
console.log(global.globalVar);
// Prints: 3
如果省略 contextObject
(或显式传递为 undefined
),将返回一个新的空 contextified 对象。
¥If contextObject
is omitted (or passed explicitly as undefined
), a new,
empty contextified object will be returned.
当新创建的上下文中的全局对象是 contextified 时,与普通全局对象相比,它有一些怪癖。例如,它不能被冻结。要创建没有上下文怪癖的上下文,请将 vm.constants.DONT_CONTEXTIFY
作为 contextObject
参数传递。有关详细信息,请参阅 vm.constants.DONT_CONTEXTIFY
的文档。
¥When the global object in the newly created context is contextified, it has some quirks
compared to ordinary global objects. For example, it cannot be frozen. To create a context
without the contextifying quirks, pass vm.constants.DONT_CONTEXTIFY
as the contextObject
argument. See the documentation of vm.constants.DONT_CONTEXTIFY
for details.
vm.createContext()
方法主要用于创建可用于运行多个脚本的单个上下文。例如,如果模拟网络浏览器,则该方法可用于创建表示窗口全局对象的单个上下文,然后在该上下文中一起运行所有 <script>
标签。
¥The vm.createContext()
method is primarily useful for creating a single
context that can be used to run multiple scripts. For instance, if emulating a
web browser, the method can be used to create a single context representing a
window's global object, then run all <script>
tags together within that
context.
提供的上下文的 name
和 origin
通过检查器 API 可见。
¥The provided name
and origin
of the context are made visible through the
Inspector API.
vm.isContext(object)
#
如果给定的 object
对象已使用 vm.createContext()
contextified,或者它是使用 vm.constants.DONT_CONTEXTIFY
创建的上下文的全局对象,则返回 true
。
¥Returns true
if the given object
object has been contextified using
vm.createContext()
, or if it's the global object of a context created
using vm.constants.DONT_CONTEXTIFY
.
vm.measureMemory([options])
#
¥Stability: 1 - Experimental
测量 V8 已知的内存并被当前 V8 隔离已知的所有上下文或主上下文使用。
¥Measure the memory known to V8 and used by all contexts known to the current V8 isolate, or the main context.
-
options
<Object> 可选的。¥
options
<Object> Optional.-
mode
<string>'summary'
或'detailed'
。在摘要模式下,只会返回为主上下文测量的内存。在详细模式下,将返回为当前 V8 隔离已知的所有上下文测量的内存。默认值:'summary'
¥
mode
<string> Either'summary'
or'detailed'
. In summary mode, only the memory measured for the main context will be returned. In detailed mode, the memory measured for all contexts known to the current V8 isolate will be returned. Default:'summary'
-
execution
<string>'default'
或'eager'
。在默认执行情况下,promise 将在下一次计划的垃圾收集开始后才会解决,这可能需要一段时间(如果程序在下一次 GC 之前退出,则永远不会)。在快速执行情况下,GC 将立即启动以测量内存。默认值:'default'
¥
execution
<string> Either'default'
or'eager'
. With default execution, the promise will not resolve until after the next scheduled garbage collection starts, which may take a while (or never if the program exits before the next GC). With eager execution, the GC will be started right away to measure the memory. Default:'default'
-
-
返回:<Promise> 如果成功测量内存,promise 将使用包含有关内存使用信息的对象进行解析。否则它将被拒绝并出现
ERR_CONTEXT_NOT_INITIALIZED
错误。¥Returns: <Promise> If the memory is successfully measured, the promise will resolve with an object containing information about the memory usage. Otherwise it will be rejected with an
ERR_CONTEXT_NOT_INITIALIZED
error.
返回的 Promise 可以解决的对象的格式特定于 V8 引擎,并且可能会从 V8 的一个版本更改为下一个版本。
¥The format of the object that the returned Promise may resolve with is specific to the V8 engine and may change from one version of V8 to the next.
返回的结果与 v8.getHeapSpaceStatistics()
返回的统计数据不同,vm.measureMemory()
测量的是 V8 引擎当前实例中每个 V8 特定上下文可访问的内存,而 v8.getHeapSpaceStatistics()
的结果测量的是当前 V8 中每个堆空间占用的内存实例。
¥The returned result is different from the statistics returned by
v8.getHeapSpaceStatistics()
in that vm.measureMemory()
measure the
memory reachable by each V8 specific contexts in the current instance of
the V8 engine, while the result of v8.getHeapSpaceStatistics()
measure
the memory occupied by each heap space in the current V8 instance.
const vm = require('node:vm');
// Measure the memory used by the main context.
vm.measureMemory({ mode: 'summary' })
// This is the same as vm.measureMemory()
.then((result) => {
// The current format is:
// {
// total: {
// jsMemoryEstimate: 2418479, jsMemoryRange: [ 2418479, 2745799 ]
// }
// }
console.log(result);
});
const context = vm.createContext({ a: 1 });
vm.measureMemory({ mode: 'detailed', execution: 'eager' })
.then((result) => {
// Reference the context here so that it won't be GC'ed
// until the measurement is complete.
console.log(context.a);
// {
// total: {
// jsMemoryEstimate: 2574732,
// jsMemoryRange: [ 2574732, 2904372 ]
// },
// current: {
// jsMemoryEstimate: 2438996,
// jsMemoryRange: [ 2438996, 2768636 ]
// },
// other: [
// {
// jsMemoryEstimate: 135736,
// jsMemoryRange: [ 135736, 465376 ]
// }
// ]
// }
console.log(result);
});
vm.runInContext(code, contextifiedObject[, options])
#
-
code
<string> 要编译和运行的 JavaScript 代码。¥
code
<string> The JavaScript code to compile and run. -
contextifiedObject
<Object>code
编译运行时将用作global
的 contextified 对象。¥
contextifiedObject
<Object> The contextified object that will be used as theglobal
when thecode
is compiled and run. -
-
filename
<string> 指定此脚本生成的堆栈跟踪中使用的文件名。默认值:'evalmachine.<anonymous>'
。¥
filename
<string> Specifies the filename used in stack traces produced by this script. Default:'evalmachine.<anonymous>'
. -
lineOffset
<number> 指定在此脚本生成的堆栈跟踪中显示的行号偏移量。默认值:0
。¥
lineOffset
<number> Specifies the line number offset that is displayed in stack traces produced by this script. Default:0
. -
columnOffset
<number> 指定在此脚本生成的堆栈跟踪中显示的第一行列号偏移量。默认值:0
。¥
columnOffset
<number> Specifies the first-line column number offset that is displayed in stack traces produced by this script. Default:0
. -
displayErrors
<boolean> 当为true
时,如果编译code
时出现Error
,则导致错误的代码行会附加到堆栈跟踪中。默认值:true
。¥
displayErrors
<boolean> Whentrue
, if anError
occurs while compiling thecode
, the line of code causing the error is attached to the stack trace. Default:true
. -
timeout
<integer> 指定终止执行前执行code
的毫秒数。如果执行终止,则将抛出Error
。此值必须是严格的正整数。¥
timeout
<integer> Specifies the number of milliseconds to executecode
before terminating execution. If execution is terminated, anError
will be thrown. This value must be a strictly positive integer. -
breakOnSigint
<boolean> 如果是true
,接收SIGINT
(Ctrl+C)将终止执行并抛出Error
。已通过process.on('SIGINT')
附加的事件的现有句柄在脚本执行期间被禁用,但在此之后继续工作。默认值:false
。¥
breakOnSigint
<boolean> Iftrue
, receivingSIGINT
(Ctrl+C) will terminate execution and throw anError
. Existing handlers for the event that have been attached viaprocess.on('SIGINT')
are disabled during script execution, but continue to work after that. Default:false
. -
cachedData
<Buffer> | <TypedArray> | <DataView> 为所提供的源提供可选的Buffer
或TypedArray
或DataView
,其中包含 V8 的代码缓存数据。¥
cachedData
<Buffer> | <TypedArray> | <DataView> Provides an optionalBuffer
orTypedArray
, orDataView
with V8's code cache data for the supplied source. -
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> 用于指定在调用import()
时评估此脚本期间应如何加载模块。此选项是实验模块 API 的一部分。不建议在生产环境中使用它。详细信息参见 编译 API 中支持动态import()
。¥
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Used to specify the how the modules should be loaded during the evaluation of this script whenimport()
is called. This option is part of the experimental modules API. We do not recommend using it in a production environment. For detailed information, see Support of dynamicimport()
in compilation APIs.
-
vm.runInContext()
方法编译 code
,在 contextifiedObject
的上下文中运行它,然后返回结果。运行代码无权访问本地作用域。contextifiedObject
对象之前必须是使用 vm.createContext()
方法的 contextified。
¥The vm.runInContext()
method compiles code
, runs it within the context of
the contextifiedObject
, then returns the result. Running code does not have
access to the local scope. The contextifiedObject
object must have been
previously contextified using the vm.createContext()
method.
如果 options
是字符串,则指定文件名。
¥If options
is a string, then it specifies the filename.
以下示例使用单个 contextified 对象编译和执行不同的脚本:
¥The following example compiles and executes different scripts using a single contextified object:
const vm = require('node:vm');
const contextObject = { globalVar: 1 };
vm.createContext(contextObject);
for (let i = 0; i < 10; ++i) {
vm.runInContext('globalVar *= 2;', contextObject);
}
console.log(contextObject);
// Prints: { globalVar: 1024 }
vm.runInNewContext(code[, contextObject[, options]])
#
-
code
<string> 要编译和运行的 JavaScript 代码。¥
code
<string> The JavaScript code to compile and run. -
contextObject
<Object> | <undefined>vm.constants.DONT_CONTEXTIFY
或将成为 contextified 的对象。如果是undefined
,将创建一个空的上下文化对象以实现向后兼容。¥
contextObject
<Object> | <undefined> Eithervm.constants.DONT_CONTEXTIFY
or an object that will be contextified. Ifundefined
, an empty contextified object will be created for backwards compatibility. -
-
filename
<string> 指定此脚本生成的堆栈跟踪中使用的文件名。默认值:'evalmachine.<anonymous>'
。¥
filename
<string> Specifies the filename used in stack traces produced by this script. Default:'evalmachine.<anonymous>'
. -
lineOffset
<number> 指定在此脚本生成的堆栈跟踪中显示的行号偏移量。默认值:0
。¥
lineOffset
<number> Specifies the line number offset that is displayed in stack traces produced by this script. Default:0
. -
columnOffset
<number> 指定在此脚本生成的堆栈跟踪中显示的第一行列号偏移量。默认值:0
。¥
columnOffset
<number> Specifies the first-line column number offset that is displayed in stack traces produced by this script. Default:0
. -
displayErrors
<boolean> 当为true
时,如果编译code
时出现Error
,则导致错误的代码行会附加到堆栈跟踪中。默认值:true
。¥
displayErrors
<boolean> Whentrue
, if anError
occurs while compiling thecode
, the line of code causing the error is attached to the stack trace. Default:true
. -
timeout
<integer> 指定终止执行前执行code
的毫秒数。如果执行终止,则将抛出Error
。此值必须是严格的正整数。¥
timeout
<integer> Specifies the number of milliseconds to executecode
before terminating execution. If execution is terminated, anError
will be thrown. This value must be a strictly positive integer. -
breakOnSigint
<boolean> 如果是true
,接收SIGINT
(Ctrl+C)将终止执行并抛出Error
。已通过process.on('SIGINT')
附加的事件的现有句柄在脚本执行期间被禁用,但在此之后继续工作。默认值:false
。¥
breakOnSigint
<boolean> Iftrue
, receivingSIGINT
(Ctrl+C) will terminate execution and throw anError
. Existing handlers for the event that have been attached viaprocess.on('SIGINT')
are disabled during script execution, but continue to work after that. Default:false
. -
contextName
<string> 新创建的上下文的可读名称。默认值:'VM Context i'
,其中i
是所创建上下文的升序数字索引。¥
contextName
<string> Human-readable name of the newly created context. Default:'VM Context i'
, wherei
is an ascending numerical index of the created context. -
contextOrigin
<string> 起源 对应于新创建的上下文,用于显示目的。来源的格式应该像 URL,但只有协议、主机和端口(如果需要),就像URL
对象的url.origin
属性的值。最值得注意的是,该字符串应省略尾部斜杠,因为它表示路径。默认值:''
。¥
contextOrigin
<string> Origin corresponding to the newly created context for display purposes. The origin should be formatted like a URL, but with only the scheme, host, and port (if necessary), like the value of theurl.origin
property of aURL
object. Most notably, this string should omit the trailing slash, as that denotes a path. Default:''
. -
contextCodeGeneration
<Object>-
strings
<boolean> 如果设置为 false,则任何对eval
或函数构造函数(Function
、GeneratorFunction
等)的调用都将抛出EvalError
。默认值:true
。¥
strings
<boolean> If set to false any calls toeval
or function constructors (Function
,GeneratorFunction
, etc) will throw anEvalError
. Default:true
. -
wasm
<boolean> 如果设置为 false,则任何编译 WebAssembly 模块的尝试都将抛出WebAssembly.CompileError
。默认值:true
。¥
wasm
<boolean> If set to false any attempt to compile a WebAssembly module will throw aWebAssembly.CompileError
. Default:true
.
-
-
cachedData
<Buffer> | <TypedArray> | <DataView> 为所提供的源提供可选的Buffer
或TypedArray
或DataView
,其中包含 V8 的代码缓存数据。¥
cachedData
<Buffer> | <TypedArray> | <DataView> Provides an optionalBuffer
orTypedArray
, orDataView
with V8's code cache data for the supplied source. -
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> 用于指定在调用import()
时评估此脚本期间应如何加载模块。此选项是实验模块 API 的一部分。不建议在生产环境中使用它。详细信息参见 编译 API 中支持动态import()
。¥
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Used to specify the how the modules should be loaded during the evaluation of this script whenimport()
is called. This option is part of the experimental modules API. We do not recommend using it in a production environment. For detailed information, see Support of dynamicimport()
in compilation APIs. -
microtaskMode
<string> 如果设置为afterEvaluate
,微任务(通过Promise
和async function
安排的任务)将在脚本运行后立即运行。在这种情况下,它们包含在timeout
和breakOnSigint
范围内。¥
microtaskMode
<string> If set toafterEvaluate
, microtasks (tasks scheduled throughPromise
s andasync function
s) will be run immediately after the script has run. They are included in thetimeout
andbreakOnSigint
scopes in that case.
-
-
返回:<any> 脚本中最后一条语句执行的结果。
¥Returns: <any> the result of the very last statement executed in the script.
此方法是 (new vm.Script(code, options)).runInContext(vm.createContext(options), options)
的快捷方式。如果 options
是字符串,则指定文件名。
¥This method is a shortcut to
(new vm.Script(code, options)).runInContext(vm.createContext(options), options)
.
If options
is a string, then it specifies the filename.
它同时做几件事:
¥It does several things at once:
-
创建一个新的上下文。
¥Creates a new context.
-
如果
contextObject
是一个对象,则使用新上下文对其进行 contextifies 操作。如果contextObject
未定义,则创建一个新对象并对其进行 contextifies 操作。如果contextObject
是vm.constants.DONT_CONTEXTIFY
,则不要 contextify 任何内容。¥If
contextObject
is an object, contextifies it with the new context. IfcontextObject
is undefined, creates a new object and contextifies it. IfcontextObject
isvm.constants.DONT_CONTEXTIFY
, don't contextify anything. -
将代码编译为 a
vm.Script
¥Compiles the code as a
vm.Script
-
在创建的上下文中运行编译代码。代码无权访问调用此方法的范围。
¥Runs the compield code within the created context. The code does not have access to the scope in which this method is called.
-
返回结果。
¥Returns the result.
以下示例编译并执行增加全局变量并设置新变量的代码。这些全局变量包含在 contextObject
中。
¥The following example compiles and executes code that increments a global
variable and sets a new one. These globals are contained in the contextObject
.
const vm = require('node:vm');
const contextObject = {
animal: 'cat',
count: 2,
};
vm.runInNewContext('count += 1; name = "kitty"', contextObject);
console.log(contextObject);
// Prints: { animal: 'cat', count: 3, name: 'kitty' }
// This would throw if the context is created from a contextified object.
// vm.constants.DONT_CONTEXTIFY allows creating contexts with ordinary global objects that
// can be frozen.
const frozenContext = vm.runInNewContext('Object.freeze(globalThis); globalThis;', vm.constants.DONT_CONTEXTIFY);
vm.runInThisContext(code[, options])
#
-
code
<string> 要编译和运行的 JavaScript 代码。¥
code
<string> The JavaScript code to compile and run. -
-
filename
<string> 指定此脚本生成的堆栈跟踪中使用的文件名。默认值:'evalmachine.<anonymous>'
。¥
filename
<string> Specifies the filename used in stack traces produced by this script. Default:'evalmachine.<anonymous>'
. -
lineOffset
<number> 指定在此脚本生成的堆栈跟踪中显示的行号偏移量。默认值:0
。¥
lineOffset
<number> Specifies the line number offset that is displayed in stack traces produced by this script. Default:0
. -
columnOffset
<number> 指定在此脚本生成的堆栈跟踪中显示的第一行列号偏移量。默认值:0
。¥
columnOffset
<number> Specifies the first-line column number offset that is displayed in stack traces produced by this script. Default:0
. -
displayErrors
<boolean> 当为true
时,如果编译code
时出现Error
,则导致错误的代码行会附加到堆栈跟踪中。默认值:true
。¥
displayErrors
<boolean> Whentrue
, if anError
occurs while compiling thecode
, the line of code causing the error is attached to the stack trace. Default:true
. -
timeout
<integer> 指定终止执行前执行code
的毫秒数。如果执行终止,则将抛出Error
。此值必须是严格的正整数。¥
timeout
<integer> Specifies the number of milliseconds to executecode
before terminating execution. If execution is terminated, anError
will be thrown. This value must be a strictly positive integer. -
breakOnSigint
<boolean> 如果是true
,接收SIGINT
(Ctrl+C)将终止执行并抛出Error
。已通过process.on('SIGINT')
附加的事件的现有句柄在脚本执行期间被禁用,但在此之后继续工作。默认值:false
。¥
breakOnSigint
<boolean> Iftrue
, receivingSIGINT
(Ctrl+C) will terminate execution and throw anError
. Existing handlers for the event that have been attached viaprocess.on('SIGINT')
are disabled during script execution, but continue to work after that. Default:false
. -
cachedData
<Buffer> | <TypedArray> | <DataView> 为所提供的源提供可选的Buffer
或TypedArray
或DataView
,其中包含 V8 的代码缓存数据。¥
cachedData
<Buffer> | <TypedArray> | <DataView> Provides an optionalBuffer
orTypedArray
, orDataView
with V8's code cache data for the supplied source. -
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> 用于指定在调用import()
时评估此脚本期间应如何加载模块。此选项是实验模块 API 的一部分。不建议在生产环境中使用它。详细信息参见 编译 API 中支持动态import()
。¥
importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> Used to specify the how the modules should be loaded during the evaluation of this script whenimport()
is called. This option is part of the experimental modules API. We do not recommend using it in a production environment. For detailed information, see Support of dynamicimport()
in compilation APIs.
-
-
返回:<any> 脚本中最后一条语句执行的结果。
¥Returns: <any> the result of the very last statement executed in the script.
vm.runInThisContext()
编译 code
,在当前 global
的上下文中运行它并返回结果。运行代码无权访问局部作用域,但可以访问当前 global
对象。
¥vm.runInThisContext()
compiles code
, runs it within the context of the
current global
and returns the result. Running code does not have access to
local scope, but does have access to the current global
object.
如果 options
是字符串,则指定文件名。
¥If options
is a string, then it specifies the filename.
以下示例说明使用 vm.runInThisContext()
和 JavaScript eval()
函数来运行相同的代码:
¥The following example illustrates using both vm.runInThisContext()
and
the JavaScript eval()
function to run the same code:
const vm = require('node:vm');
let localVar = 'initial value';
const vmResult = vm.runInThisContext('localVar = "vm";');
console.log(`vmResult: '${vmResult}', localVar: '${localVar}'`);
// Prints: vmResult: 'vm', localVar: 'initial value'
const evalResult = eval('localVar = "eval";');
console.log(`evalResult: '${evalResult}', localVar: '${localVar}'`);
// Prints: evalResult: 'eval', localVar: 'eval'
因为 vm.runInThisContext()
无权访问本地作用域,所以 localVar
不变。相比之下,eval()
确实可以访问本地范围,因此更改了 localVar
的值。这样 vm.runInThisContext()
很像 间接 eval()
调用,例如 (0,eval)('code')
。
¥Because vm.runInThisContext()
does not have access to the local scope,
localVar
is unchanged. In contrast, eval()
does have access to the
local scope, so the value localVar
is changed. In this way
vm.runInThisContext()
is much like an indirect eval()
call, e.g.
(0,eval)('code')
.
示例:在虚拟机中运行 HTTP 服务器#
¥Example: Running an HTTP server within a VM
当使用 script.runInThisContext()
或 vm.runInThisContext()
时,代码在当前 V8 全局上下文中执行。传给此 VM 上下文的代码将有自己的隔离作用域。
¥When using either script.runInThisContext()
or
vm.runInThisContext()
, the code is executed within the current V8 global
context. The code passed to this VM context will have its own isolated scope.
为了使用 node:http
模块运行简单的 web 服务器,传给上下文的代码必须要么自己调用 require('node:http')
,要么有对传给它的 node:http
模块的引用。例如:
¥In order to run a simple web server using the node:http
module the code passed
to the context must either call require('node:http')
on its own, or have a
reference to the node:http
module passed to it. For instance:
'use strict';
const vm = require('node:vm');
const code = `
((require) => {
const http = require('node:http');
http.createServer((request, response) => {
response.writeHead(200, { 'Content-Type': 'text/plain' });
response.end('Hello World\\n');
}).listen(8124);
console.log('Server running at http://127.0.0.1:8124/');
})`;
vm.runInThisContext(code)(require);
上述案例中的 require()
与其传入的上下文共享状态。当执行不受信任的代码时,这可能会带来风险,例如以不需要的方式更改上下文中的对象。
¥The require()
in the above case shares the state with the context it is
passed from. This may introduce risks when untrusted code is executed, e.g.
altering objects in the context in unwanted ways.
"contextify" 一个对象是什么意思?#
¥What does it mean to "contextify" an object?
在 Node.js 中执行的所有 JavaScript 都在 "context" 的范围内运行。根据 V8 嵌入器指南:
¥All JavaScript executed within Node.js runs within the scope of a "context". According to the V8 Embedder's Guide:
在 V8 中,上下文是一个执行环境,它允许独立的、不相关的 JavaScript 应用在 V8 的单个实例中运行。你必须明确指定要运行任何 JavaScript 代码的上下文。
¥In V8, a context is an execution environment that allows separate, unrelated, JavaScript applications to run in a single instance of V8. You must explicitly specify the context in which you want any JavaScript code to be run.
当使用对象调用方法 vm.createContext()
时,contextObject
参数将用于封装 V8 上下文新实例的全局对象(如果 contextObject
是 undefined
,则在上下文化之前将从当前上下文创建一个新对象)。这个 V8 上下文使用 node:vm
模块的方法提供了 code
运行,它可以在隔离的全局环境中运行。创建 V8 上下文并将其与外部上下文中的 contextObject
关联的过程就是本文档所称的 "contextifying" 对象。
¥When the method vm.createContext()
is called with an object, the contextObject
argument
will be used to wrap the global object of a new instance of a V8 Context
(if contextObject
is undefined
, a new object will be created from the current context
before its contextified). This V8 Context provides the code
run using the node:vm
module's methods with an isolated global environment within which it can operate.
The process of creating the V8 Context and associating it with the contextObject
in the outer context is what this document refers to as "contextifying" the object.
上下文化会给上下文中的 globalThis
值带来一些怪癖。例如,它不能被冻结,并且它在外部上下文中不等于 contextObject
的引用。
¥The contextifying would introduce some quirks to the globalThis
value in the context.
For example, it cannot be frozen, and it is not reference equal to the contextObject
in the outer context.
const vm = require('node:vm');
// An undefined `contextObject` option makes the global object contextified.
let context = vm.createContext();
console.log(vm.runInContext('globalThis', context) === context); // false
// A contextified global object cannot be frozen.
try {
vm.runInContext('Object.freeze(globalThis);', context);
} catch(e) {
console.log(e); // TypeError: Cannot freeze
}
console.log(vm.runInContext('globalThis.foo = 1; foo;', context)); // 1
要使用普通全局对象创建上下文并以较少的怪癖访问外部上下文中的全局代理,请将 vm.constants.DONT_CONTEXTIFY
指定为 contextObject
参数。
¥To create a context with an ordinary global object and get access to a global proxy in
the outer context with fewer quirks, specify vm.constants.DONT_CONTEXTIFY
as the
contextObject
argument.
vm.constants.DONT_CONTEXTIFY
#
当此常量用作 vm API 中的 contextObject
参数时,它会指示 Node.js 创建上下文,而无需以 Node.js 特定的方式将其全局对象与另一个对象封装在一起。因此,新上下文中的 globalThis
值将更接近普通值。
¥This constant, when used as the contextObject
argument in vm APIs, instructs Node.js to create
a context without wrapping its global object with another object in a Node.js-specific manner.
As a result, the globalThis
value inside the new context would behave more closely to an ordinary
one.
const vm = require('node:vm');
// Use vm.constants.DONT_CONTEXTIFY to freeze the global object.
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
}
当 vm.constants.DONT_CONTEXTIFY
用作 vm.createContext()
的 contextObject
参数时,返回的对象是新创建的上下文中的全局对象的代理类对象,具有较少的 Node.js 特定怪癖。它在新上下文中引用等于 globalThis
值,可以从上下文外部进行修改,并且可用于直接访问新上下文中的内置函数。
¥When vm.constants.DONT_CONTEXTIFY
is used as the contextObject
argument to vm.createContext()
,
the returned object is a proxy-like object to the global object in the newly created context with
fewer Node.js-specific quirks. It is reference equal to the globalThis
value in the new context,
can be modified from outside the context, and can be used to access built-ins in the new context directly.
const vm = require('node:vm');
const context = vm.createContext(vm.constants.DONT_CONTEXTIFY);
// Returned object is reference equal to globalThis in the new context.
console.log(vm.runInContext('globalThis', context) === context); // true
// Can be used to access globals in the new context directly.
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
// Can be frozen and it affects the inner context.
Object.freeze(context);
try {
vm.runInContext('baz = 1; baz;', context);
} catch(e) {
console.log(e); // Uncaught ReferenceError: baz is not defined
}
与异步任务和 Promises 的超时交互#
¥Timeout interactions with asynchronous tasks and Promises
Promise
和 async function
可以异步调度 JavaScript 引擎运行的任务。默认情况下,这些任务在当前堆栈上的所有 JavaScript 函数执行完毕后运行。这允许转义 timeout
和 breakOnSigint
选项的功能。
¥Promise
s and async function
s can schedule tasks run by the JavaScript
engine asynchronously. By default, these tasks are run after all JavaScript
functions on the current stack are done executing.
This allows escaping the functionality of the timeout
and
breakOnSigint
options.
例如,以下代码由 vm.runInNewContext()
执行,超时时间为 5 毫秒,它安排了一个无限循环在 promise 解决后运行。计划的循环永远不会被超时中断:
¥For example, the following code executed by vm.runInNewContext()
with a
timeout of 5 milliseconds schedules an infinite loop to run after a promise
resolves. The scheduled loop is never interrupted by the 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 },
);
// This is printed *before* 'entering loop' (!)
console.log('done executing');
这可以通过将 microtaskMode: 'afterEvaluate'
传给创建 Context
的代码来解决:
¥This can be addressed by passing microtaskMode: 'afterEvaluate'
to the code
that creates the 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' },
);
在这种情况下,通过 promise.then()
调度的微任务将在从 vm.runInNewContext()
返回之前运行,并会被 timeout
功能中断。这仅适用于在 vm.Context
中运行的代码,因此例如 vm.runInThisContext()
不采用此选项。
¥In this case, the microtask scheduled through promise.then()
will be run
before returning from vm.runInNewContext()
, and will be interrupted
by the timeout
functionality. This applies only to code running in a
vm.Context
, so e.g. vm.runInThisContext()
does not take this option.
Promise 回调被输入到创建它们的上下文的微任务队列中。例如,如果在上面的例子中 () => loop()
只被 loop
替换,那么 loop
将被推入全局微任务队列,因为它是来自外部(主)上下文的函数,因此也将能够脱离超时。
¥Promise callbacks are entered into the microtask queue of the context in which
they were created. For example, if () => loop()
is replaced with just loop
in the above example, then loop
will be pushed into the global microtask
queue, because it is a function from the outer (main) context, and thus will
also be able to escape the timeout.
如果 process.nextTick()
、queueMicrotask()
、setTimeout()
、setImmediate()
等异步调度函数在 vm.Context
中可用,传递给它们的函数将被添加到全局队列中,全局队列由所有上下文共享。因此,传给这些函数的回调也无法通过超时控制。
¥If asynchronous scheduling functions such as process.nextTick()
,
queueMicrotask()
, setTimeout()
, setImmediate()
, etc. are made available
inside a vm.Context
, functions passed to them will be added to global queues,
which are shared by all contexts. Therefore, callbacks passed to those functions
are not controllable through the timeout either.
编译 API 中支持动态 import()
#
¥Support of dynamic import()
in compilation APIs
以下 API 支持 importModuleDynamically
选项,以在 vm 模块编译的代码中启用动态 import()
。
¥The following APIs support an importModuleDynamically
option to enable dynamic
import()
in code compiled by the vm module.
-
new vm.Script
-
vm.compileFunction()
-
new vm.SourceTextModule
-
vm.runInThisContext()
-
vm.runInContext()
-
vm.runInNewContext()
-
vm.createContext()
此选项仍然是实验模块 API 的一部分。不建议在生产环境中使用它。
¥This option is still part of the experimental modules API. We do not recommend using it in a production environment.
当未指定或未定义 importModuleDynamically
选项时#
¥When the importModuleDynamically
option is not specified or undefined
如果未指定此选项,或者如果是 undefined
,则包含 import()
的代码仍可以由 vm API 编译,但当执行编译后的代码并实际调用 import()
时,结果将拒绝并显示 ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING
。
¥If this option is not specified, or if it's undefined
, code containing
import()
can still be compiled by the vm APIs, but when the compiled code is
executed and it actually calls import()
, the result will reject with
ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING
.
当 importModuleDynamically
为 vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER
时#
¥When importModuleDynamically
is vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER
vm.SourceTextModule
目前不支持此选项。
¥This option is currently not supported for vm.SourceTextModule
.
使用此选项,当在编译的代码中启动 import()
时,Node.js 将使用主上下文中的默认 ESM 加载器来加载请求的模块并将其返回到正在执行的代码。
¥With this option, when an import()
is initiated in the compiled code, Node.js
would use the default ESM loader from the main context to load the requested
module and return it to the code being executed.
这使得正在编译的代码可以访问 Node.js 内置模块,例如 fs
或 http
。如果代码在不同的上下文中执行,请注意从主上下文加载的模块创建的对象仍然来自主上下文,而不是新上下文中的 instanceof
内置类。
¥This gives access to Node.js built-in modules such as fs
or http
to the code being compiled. If the code is executed in a different context,
be aware that the objects created by modules loaded from the main context
are still from the main context and not instanceof
built-in classes in the
new context.
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 loaded from the main context is not an instance of the Function
// class in the new context.
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 loaded from the main context is not an instance of the Function
// class in the new context.
script.runInNewContext().then(console.log);
此选项还允许脚本或函数加载用户模块:
¥This option also allows the script or function to load user modules:
import { Script, constants } from 'node:vm';
import { resolve } from 'node:path';
import { writeFileSync } from 'node:fs';
// Write test.js and test.txt to the directory where the current script
// being run is located.
writeFileSync(resolve(import.meta.dirname, 'test.mjs'),
'export const filename = "./test.json";');
writeFileSync(resolve(import.meta.dirname, 'test.json'),
'{"hello": "world"}');
// Compile a script that loads test.mjs and then test.json
// as if the script is placed in the same 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');
// Write test.js and test.txt to the directory where the current script
// being run is located.
writeFileSync(resolve(__dirname, 'test.mjs'),
'export const filename = "./test.json";');
writeFileSync(resolve(__dirname, 'test.json'),
'{"hello": "world"}');
// Compile a script that loads test.mjs and then test.json
// as if the script is placed in the same 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);
使用主上下文中的默认加载器加载用户模块有一些注意事项:
¥There are a few caveats with loading user modules using the default loader from the main context:
-
正在解析的模块将与传递给
vm.Script
或vm.compileFunction()
的filename
选项相关。该解析可以使用绝对路径或 URL 字符串的filename
。如果filename
是一个既不是绝对路径也不是 URL 的字符串,或者未定义,则解析将相对于进程的当前工作目录。在vm.createContext()
的情况下,解析始终相对于当前工作目录,因为仅当没有引用脚本或模块时才使用此选项。¥The module being resolved would be relative to the
filename
option passed tovm.Script
orvm.compileFunction()
. The resolution can work with afilename
that's either an absolute path or a URL string. Iffilename
is a string that's neither an absolute path or a URL, or if it's undefined, the resolution will be relative to the current working directory of the process. In the case ofvm.createContext()
, the resolution is always relative to the current working directory since this option is only used when there isn't a referrer script or module. -
对于解析为特定路径的任何给定
filename
,一旦进程设法从该路径加载特定模块,结果可能会被缓存,并且从同一路径加载同一模块的后续加载将返回相同的内容。如果filename
是一个 URL 字符串,那么如果它具有不同的搜索参数,则不会命中缓存。对于不是 URL 字符串的filename
,目前无法绕过缓存行为。¥For any given
filename
that resolves to a specific path, once the process manages to load a particular module from that path, the result may be cached, and subsequent load of the same module from the same path would return the same thing. If thefilename
is a URL string, the cache would not be hit if it has different search parameters. Forfilename
s that are not URL strings, there is currently no way to bypass the caching behavior.
当 importModuleDynamically
是函数时#
¥When importModuleDynamically
is a function
当 importModuleDynamically
是一个函数时,当编译代码中调用 import()
时,它将被调用,以便用户自定义所请求的模块应如何编译和评估。目前,必须使用 --experimental-vm-modules
标志启动 Node.js 实例才能使此选项发挥作用。如果未设置该标志,则该回调将被忽略。如果评估的代码实际上调用了 import()
,则结果将拒绝并显示 ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAG
。
¥When importModuleDynamically
is a function, it will be invoked when import()
is called in the compiled code for users to customize how the requested module
should be compiled and evaluated. Currently, the Node.js instance must be
launched with the --experimental-vm-modules
flag for this option to work. If
the flag isn't set, this callback will be ignored. If the code evaluated
actually calls to import()
, the result will reject with
ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAG
.
回调 importModuleDynamically(specifier, referrer, importAttributes)
具有以下签名:
¥The callback importModuleDynamically(specifier, referrer, importAttributes)
has the following signature:
-
specifier
<string> 说明符传递给import()
¥
specifier
<string> specifier passed toimport()
-
referrer
<vm.Script> | <Function> | <vm.SourceTextModule> | <Object> 引用者是针对new vm.Script
、vm.runInThisContext
、vm.runInContext
和vm.runInNewContext
编译的vm.Script
。vm.compileFunction
是编译后的Function
,new vm.SourceTextModule
是编译后的vm.SourceTextModule
,vm.createContext()
是上下文Object
。¥
referrer
<vm.Script> | <Function> | <vm.SourceTextModule> | <Object> The referrer is the compiledvm.Script
fornew vm.Script
,vm.runInThisContext
,vm.runInContext
andvm.runInNewContext
. It's the compiledFunction
forvm.compileFunction
, the compiledvm.SourceTextModule
fornew vm.SourceTextModule
, and the contextObject
forvm.createContext()
. -
importAttributes
<Object> 传给optionsExpression
可选参数的"with"
值,如果没有提供值,则为空对象。¥
importAttributes
<Object> The"with"
value passed to theoptionsExpression
optional parameter, or an empty object if no value was provided. -
返回:<Module Namespace Object> | <vm.Module> 建议返回
vm.Module
以利用错误跟踪,并避免包含then
函数导出的命名空间出现问题。¥Returns: <Module Namespace Object> | <vm.Module> Returning a
vm.Module
is recommended in order to take advantage of error tracking, and to avoid issues with namespaces that containthen
function exports.
// This script must be run with --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); // The compiled script
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' } }
// This script must be run with --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); // The compiled script
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' } }
})();