- assert 断言
- async_hooks 异步钩子
- async_hooks/context 异步上下文
- buffer 缓冲区
- C++插件
- C/C++插件(使用 Node-API)
- C++嵌入器
- child_process 子进程
- cluster 集群
- CLI 命令行
- console 控制台
- crypto 加密
- crypto/webcrypto 网络加密
- debugger 调试器
- deprecation 弃用
- dgram 数据报
- diagnostics_channel 诊断通道
- dns 域名服务器
- domain 域
- env 环境变量
- 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 单个可执行应用程序
- sqlite 轻型数据库
- stream 流
- stream/web 网络流
- string_decoder 字符串解码器
- test 测试
- timers 定时器
- tls 安全传输层
- trace_events 跟踪事件
- tty 终端
- url 网址
- util 实用工具
- v8 引擎
- vm 虚拟机
- wasi 网络汇编系统接口
- worker_threads 工作线程
- zlib 压缩
Node.js v25.3.0 文档
- Node.js v25.3.0
- 目录
-
导航
- assert 断言
- async_hooks 异步钩子
- async_hooks/context 异步上下文
- buffer 缓冲区
- C++插件
- C/C++插件(使用 Node-API)
- C++嵌入器
- child_process 子进程
- cluster 集群
- CLI 命令行
- console 控制台
- crypto 加密
- crypto/webcrypto 网络加密
- debugger 调试器
- deprecation 弃用
- dgram 数据报
- diagnostics_channel 诊断通道
- dns 域名服务器
- domain 域
- env 环境变量
- 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 单个可执行应用程序
- sqlite 轻型数据库
- stream 流
- stream/web 网络流
- string_decoder 字符串解码器
- test 测试
- timers 定时器
- tls 安全传输层
- trace_events 跟踪事件
- tty 终端
- url 网址
- util 实用工具
- v8 引擎
- vm 虚拟机
- wasi 网络汇编系统接口
- worker_threads 工作线程
- zlib 压缩
- 其他版本
域#>
【Domain】
源代码: lib/domain.js
此模块正在等待弃用。 一旦替代的 API 确定,该模块将被完全弃用。大多数开发者不需要使用此模块。那些确实需要域提供的功能的用户可以暂时依赖它,但将来应预计需要迁移到其他解决方案。
域提供了一种将多个不同的 IO 操作作为单个组来处理的方法。如果注册到域的任何事件触发器或回调发出 'error' 事件,或抛出错误,则域对象将被通知,而不是在 process.on('uncaughtException') 处理程序中丢失错误的上下文,或导致程序立即以错误代码退出。
【Domains provide a way to handle multiple different IO operations as a
single group. If any of the event emitters or callbacks registered to a
domain emit an 'error' event, or throw an error, then the domain object
will be notified, rather than losing the context of the error in the
process.on('uncaughtException') handler, or causing the program to
exit immediately with an error code.】
警告:不要忽视错误!#>
【Warning: Don't ignore errors!】
域错误处理器不能替代在发生错误时关闭进程。
【Domain error handlers are not a substitute for closing down a process when an error occurs.】
由于 throw 在 JavaScript 中的工作方式的本质,几乎没有任何方法可以安全地“从中断处继续”,而不会泄露引用或产生其他某种未定义的脆弱状态。
【By the very nature of how throw works in JavaScript, there is almost
never any way to safely "pick up where it left off", without leaking
references, or creating some other sort of undefined brittle state.】
对抛出的错误做出最安全的响应方式是关闭进程。当然,在一个普通的 Web 服务器中,可能有许多打开的连接,因为别人的操作触发了错误而突然关闭这些连接是不合理的。
【The safest way to respond to a thrown error is to shut down the process. Of course, in a normal web server, there may be many open connections, and it is not reasonable to abruptly shut those down because an error was triggered by someone else.】
更好的做法是向触发错误的请求发送错误响应,同时让其他请求在其正常时间内完成,并在该工作线程中停止监听新请求。
【The better approach is to send an error response to the request that triggered the error, while letting the others finish in their normal time, and stop listening for new requests in that worker.】
通过这种方式,domain 的使用与 cluster 模块密切相关,因为主进程可以在工作进程遇到错误时派生一个新的工作进程。对于可扩展到多台机器的 Node.js 程序,终止的代理或服务注册表可以注意到失败,并相应地做出反应。
【In this way, domain usage goes hand-in-hand with the cluster module,
since the primary process can fork a new worker when a worker
encounters an error. For Node.js programs that scale to multiple
machines, the terminating proxy or service registry can take note of
the failure, and react accordingly.】
例如,这不是一个好主意:
【For example, this is not a good idea:】
// XXX WARNING! BAD IDEA!
const d = require('node:domain').create();
d.on('error', (er) => {
// The error won't crash the process, but what it does is worse!
// Though we've prevented abrupt process restarting, we are leaking
// a lot of resources if this ever happens.
// This is no better than process.on('uncaughtException')!
console.log(`error, but oh well ${er.message}`);
});
d.run(() => {
require('node:http').createServer((req, res) => {
handleRequest(req, res);
}).listen(PORT);
});
通过利用字段的上下文,以及将我们的程序分成多个工作进程的弹性,我们可以更恰当地做出反应,并以更高的安全性处理错误。
【By using the context of a domain, and the resilience of separating our program into multiple worker processes, we can react more appropriately, and handle errors with much greater safety.】
// Much better!
const cluster = require('node:cluster');
const PORT = +process.env.PORT || 1337;
if (cluster.isPrimary) {
// A more realistic scenario would have more than 2 workers,
// and perhaps not put the primary and worker in the same file.
//
// It is also possible to get a bit fancier about logging, and
// implement whatever custom logic is needed to prevent DoS
// attacks and other bad behavior.
//
// See the options in the cluster documentation.
//
// The important thing is that the primary does very little,
// increasing our resilience to unexpected errors.
cluster.fork();
cluster.fork();
cluster.on('disconnect', (worker) => {
console.error('disconnect!');
cluster.fork();
});
} else {
// the worker
//
// This is where we put our bugs!
const domain = require('node:domain');
// See the cluster documentation for more details about using
// worker processes to serve requests. How it works, caveats, etc.
const server = require('node:http').createServer((req, res) => {
const d = domain.create();
d.on('error', (er) => {
console.error(`error ${er.stack}`);
// We're in dangerous territory!
// By definition, something unexpected occurred,
// which we probably didn't want.
// Anything can happen now! Be very careful!
try {
// Make sure we close down within 30 seconds
const killtimer = setTimeout(() => {
process.exit(1);
}, 30000);
// But don't keep the process open just for that!
killtimer.unref();
// Stop taking new requests.
server.close();
// Let the primary know we're dead. This will trigger a
// 'disconnect' in the cluster primary, and then it will fork
// a new worker.
cluster.worker.disconnect();
// Try to send an error to the request that triggered the problem
res.statusCode = 500;
res.setHeader('content-type', 'text/plain');
res.end('Oops, there was a problem!\n');
} catch (er2) {
// Oh well, not much we can do at this point.
console.error(`Error sending 500! ${er2.stack}`);
}
});
// Because req and res were created before this domain existed,
// we need to explicitly add them.
// See the explanation of implicit vs explicit binding below.
d.add(req);
d.add(res);
// Now run the handler function in the domain.
d.run(() => {
handleRequest(req, res);
});
});
server.listen(PORT);
}
// This part is not important. Just an example routing thing.
// Put fancy application logic here.
function handleRequest(req, res) {
switch (req.url) {
case '/error':
// We do some async stuff, and then...
setTimeout(() => {
// Whoops!
flerb.bark();
}, timeout);
break;
default:
res.end('ok');
}
}
Error 对象的扩展#>
【Additions to Error objects】
每当一个 Error 对象通过域传递时,会向其添加一些额外的字段。
【Any time an Error object is routed through a domain, a few extra fields
are added to it.】
error.domain首先处理该错误的域。error.domainEmitter发出'error'事件的事件触发器,该事件携带错误对象。error.domainBound绑定到域的回调函数,第一个参数传入错误对象。error.domainThrown一个布尔值,表示错误是否被抛出、发出或传递给绑定的回调函数。
隐式绑定#>
【Implicit binding】
如果域正在使用,那么所有新的 EventEmitter 对象(包括 Stream 对象、请求、响应等)将在创建时隐式绑定到活动域。
【If domains are in use, then all new EventEmitter objects (including
Stream objects, requests, responses, etc.) will be implicitly bound to
the active domain at the time of their creation.】
此外,传递给底层事件循环请求(例如 fs.open() 或其他使用回调的方法)的回调将自动绑定到活动域。如果它们抛出异常,域将捕获该错误。
【Additionally, callbacks passed to low-level event loop requests (such as
to fs.open(), or other callback-taking methods) will automatically be
bound to the active domain. If they throw, then the domain will catch
the error.】
为了防止过度使用内存,Domain 对象本身不会被隐式添加为活动域的子对象。如果这样做,就很容易导致请求和响应对象无法被正确地垃圾回收。
【In order to prevent excessive memory usage, Domain objects themselves
are not implicitly added as children of the active domain. If they
were, then it would be too easy to prevent request and response objects
from being properly garbage collected.】
要将 Domain 对象作为父 Domain 的子对象进行嵌套,必须显式添加它们。
【To nest Domain objects as children of a parent Domain they must be
explicitly added.】
隐式绑定会将抛出的错误和 'error' 事件抛送到 Domain 的 'error' 事件,但不会在 Domain 上注册 EventEmitter。隐式绑定仅处理抛出的错误和 'error' 事件。
【Implicit binding routes thrown errors and 'error' events to the
Domain's 'error' event, but does not register the EventEmitter on the
Domain.
Implicit binding only takes care of thrown errors and 'error' events.】
显式绑定#>
【Explicit binding】
有时,正在使用的域并不是某个特定事件触发器应该使用的域。或者,事件触发器可能是在一个域的上下文中创建的,但本应绑定到另一个域。
【Sometimes, the domain in use is not the one that ought to be used for a specific event emitter. Or, the event emitter could have been created in the context of one domain, but ought to instead be bound to some other domain.】
例如,可能有一个域名用于 HTTP 服务器,但我们可能希望为每个请求使用一个单独的域名。
【For example, there could be one domain in use for an HTTP server, but perhaps we would like to have a separate domain to use for each request.】
这可以通过显式绑定来实现。
【That is possible via explicit binding.】
// Create a top-level domain for the server
const domain = require('node:domain');
const http = require('node:http');
const serverDomain = domain.create();
serverDomain.run(() => {
// Server is created in the scope of serverDomain
http.createServer((req, res) => {
// Req and res are also created in the scope of serverDomain
// however, we'd prefer to have a separate domain for each request.
// create it first thing, and add req and res to it.
const reqd = domain.create();
reqd.add(req);
reqd.add(res);
reqd.on('error', (er) => {
console.error('Error', er, req.url);
try {
res.writeHead(500);
res.end('Error occurred, sorry.');
} catch (er2) {
console.error('Error sending 500', er2, req.url);
}
});
}).listen(1337);
});
domain.create()#>
- 返回:<Domain>
类:Domain#>
【Class: Domain】
Domain 类封装了将错误和未捕获异常路由到活动 Domain 对象的功能。
【The Domain class encapsulates the functionality of routing errors and
uncaught exceptions to the active Domain object.】
要处理它捕获的错误,请监听它的 'error' 事件。
【To handle the errors that it catches, listen to its 'error' event.】
domain.members#>
- 类型:<Array>
一组已被明确添加到域中的定时器和事件触发器。
【An array of timers and event emitters that have been explicitly added to the domain.】
domain.add(emitter)#>
emitter<EventEmitter> | <Timer> 要添加到域的触发器或定时器
明确地将一个触发器添加到域中。如果由触发器调用的任何事件处理程序抛出错误,或者触发器发出 'error' 事件,它将像隐式绑定一样被路由到域的 'error' 事件。
【Explicitly adds an emitter to the domain. If any event handlers called by
the emitter throw an error, or if the emitter emits an 'error' event, it
will be routed to the domain's 'error' event, just like with implicit
binding.】
这同样适用于从 setInterval() 和 setTimeout() 返回的定时器。如果它们的回调函数抛出错误,将会被域的 'error' 处理程序捕获。
【This also works with timers that are returned from setInterval() and
setTimeout(). If their callback function throws, it will be caught by
the domain 'error' handler.】
如果计时器或 EventEmitter 已经绑定到了某个域,它会从该域中移除,并绑定到这个域。
【If the Timer or EventEmitter was already bound to a domain, it is removed
from that one, and bound to this one instead.】
domain.bind(callback)#>
callback<Function> 回调函数- 返回:<Function> 绑定的函数
返回的函数将会是对提供的回调函数的一个封装。当调用返回的函数时,抛出的任何错误都会被路由到域的 'error' 事件。
【The returned function will be a wrapper around the supplied callback
function. When the returned function is called, any errors that are
thrown will be routed to the domain's 'error' event.】
const d = domain.create();
function readSomeFile(filename, cb) {
fs.readFile(filename, 'utf8', d.bind((er, data) => {
// If this throws, it will also be passed to the domain.
return cb(er, data ? JSON.parse(data) : null);
}));
}
d.on('error', (er) => {
// An error occurred somewhere. If we throw it now, it will crash the program
// with the normal line number and stack message.
});
domain.enter()#>
enter() 方法是由 run()、bind() 和 intercept() 方法使用的底层机制,用于设置活动域。它将 domain.active 和 process.domain 设置为该域,并隐式地将该域推入由 domain 模块管理的域栈(有关域栈的详细信息,请参见 domain.exit())。调用 enter() 标志着与域绑定的一链异步调用和 I/O 操作的开始。
【The enter() method is plumbing used by the run(), bind(), and
intercept() methods to set the active domain. It sets domain.active and
process.domain to the domain, and implicitly pushes the domain onto the domain
stack managed by the domain module (see domain.exit() for details on the
domain stack). The call to enter() delimits the beginning of a chain of
asynchronous calls and I/O operations bound to a domain.】
调用 enter() 只会改变活动域,并不会修改域本身。enter() 和 exit() 可以在同一个域上任意次调用。
【Calling enter() changes only the active domain, and does not alter the domain
itself. enter() and exit() can be called an arbitrary number of times on a
single domain.】
domain.exit()#>
exit() 方法退出当前域,将其从域堆栈中弹出。每当执行将切换到不同异步调用链的上下文时,确保当前域已被退出是很重要的。调用 exit() 标志着绑定到域的异步调用链和 I/O 操作的结束或中断。
【The exit() method exits the current domain, popping it off the domain stack.
Any time execution is going to switch to the context of a different chain of
asynchronous calls, it's important to ensure that the current domain is exited.
The call to exit() delimits either the end of or an interruption to the chain
of asynchronous calls and I/O operations bound to a domain.】
如果有多个嵌套的域绑定到当前执行上下文,exit() 将退出嵌套在该域内的任何域。
【If there are multiple, nested domains bound to the current execution context,
exit() will exit any domains nested within this domain.】
调用 exit() 只会改变当前活动的域,并不会修改域本身。enter() 和 exit() 可以在同一个域上任意次数地调用。
【Calling exit() changes only the active domain, and does not alter the domain
itself. enter() and exit() can be called an arbitrary number of times on a
single domain.】
domain.intercept(callback)#>
callback<Function> 回调函数- 返回:<Function> 被拦截的函数
此方法几乎与 domain.bind(callback) 相同。然而,除了捕获抛出的错误外,它还会拦截作为函数第一个参数传入的 Error 对象。
【This method is almost identical to domain.bind(callback). However, in
addition to catching thrown errors, it will also intercept Error
objects sent as the first argument to the function.】
通过这种方式,常见的 if (err) return callback(err); 模式可以被单个地方的统一错误处理器所取代。
【In this way, the common if (err) return callback(err); pattern can be replaced
with a single error handler in a single place.】
const d = domain.create();
function readSomeFile(filename, cb) {
fs.readFile(filename, 'utf8', d.intercept((data) => {
// Note, the first argument is never passed to the
// callback since it is assumed to be the 'Error' argument
// and thus intercepted by the domain.
// If this throws, it will also be passed to the domain
// so the error-handling logic can be moved to the 'error'
// event on the domain instead of being repeated throughout
// the program.
return cb(null, JSON.parse(data));
}));
}
d.on('error', (er) => {
// An error occurred somewhere. If we throw it now, it will crash the program
// with the normal line number and stack message.
});
domain.remove(emitter)#>
emitter<EventEmitter> | <Timer> 触发器或计时器将从域中移除
domain.add(emitter) 的相反。移除指定触发器的域处理。
【The opposite of domain.add(emitter). Removes domain handling from the
specified emitter.】
domain.run(fn[, ...args])#>
fn<Function>...args<any>
在该域的上下文中运行提供的函数,隐式绑定在该上下文中创建的所有事件触发器、计时器和低级请求。可以选择向函数传递参数。
【Run the supplied function in the context of the domain, implicitly binding all event emitters, timers, and low-level requests that are created in that context. Optionally, arguments can be passed to the function.】
这是使用域的最基本方式。
【This is the most basic way to use a domain.】
const domain = require('node:domain');
const fs = require('node:fs');
const d = domain.create();
d.on('error', (er) => {
console.error('Caught error!', er);
});
d.run(() => {
process.nextTick(() => {
setTimeout(() => { // Simulating some various async stuff
fs.open('non-existent file', 'r', (er, fd) => {
if (er) throw er;
// proceed...
});
}, 100);
});
});
在这个例子中,d.on('error') 处理程序会被触发,而不会导致程序崩溃。
【In this example, the d.on('error') handler will be triggered, rather
than crashing the program.】
域和 promise#>
【Domains and promises】
从 Node.js 8.0.0 开始,Promise 的处理程序会在调用 .then() 或 .catch() 时所在的域中执行:
【As of Node.js 8.0.0, the handlers of promises are run inside the domain in
which the call to .then() or .catch() itself was made:】
const d1 = domain.create();
const d2 = domain.create();
let p;
d1.run(() => {
p = Promise.resolve(42);
});
d2.run(() => {
p.then((v) => {
// running in d2
});
});
可以使用 domain.bind(callback) 将回调绑定到特定域:
【A callback may be bound to a specific domain using domain.bind(callback):】
const d1 = domain.create();
const d2 = domain.create();
let p;
d1.run(() => {
p = Promise.resolve(42);
});
d2.run(() => {
p.then(p.domain.bind((v) => {
// running in d1
}));
});
域不会干扰 Promise 的错误处理机制。换句话说,对于未处理的 Promise 拒绝,不会触发任何 'error' 事件。
【Domains will not interfere with the error handling mechanisms for
promises. In other words, no 'error' event will be emitted for unhandled
Promise rejections.】