Node.js 解释Domain概念
介绍: Node.js的domain模块用于捕捉未处理的错误。域提供了处理多个不同输入输出操作的方式,作为一个单一的组。如果事件触发器或回调在域中注册,当发生错误事件或抛出错误时,域对象会被通知而不会丢失错误的上下文。域错误处理程序不能替代在发生错误时关闭进程。处理抛出的错误的最安全的方式是关闭它,终止进程。建议一个典型的web服务器发送一个错误响应给抛出错误的请求,并允许其他成员在正常的时间内完成,并停止监听来自该工作进程的新请求。
未处理的错误可以使用内部绑定或外部绑定进行拦截。
- 内部绑定: 错误事件发射器在域的
run
方法中执行代码。在域上下文中执行提供的函数,并且隐式地绑定在该上下文中创建的事件触发器、定时器和底层请求。可以选择传递参数给函数。 - 外部绑定: 错误事件发射器使用其
add
方法将其明确添加到域中。它明确地将发射器添加到域中。如果发射器调用的事件处理程序抛出错误,或者如果发射器触发了”error”事件,它将被转发到域的”error”事件,类似于隐式绑定。这也适用于setInterval()
和setTimeout()
返回的定时器。当回调函数被调用时,它会被域的”error”处理程序捕获。
语法: 要使用域模块,我们需要将其导入到项目目录中。语法如下:
const domain = require("domain");
注意: 根据官方的Node.js文档,这个域模块即将过时。一旦替代的API完成,这个模块将被完全弃用。现在,那些绝对需要域提供的功能的用户可以暂时信任它,但未来应该期待转移到其他解决方案。现在我们不应该尝试使用它们来编写新的代码。
域模块的域类用于为活动域对象提供路由错误和未捕获的异常。这是EventEmitter的子类。要处理捕获的错误,请监听错误事件。可以使用以下语法创建它。
const domain = require("domain");
const createdDomain = domain.create();
示例1: 这个示例将演示在Node.js中的域:
const EventEmitter = require("events").EventEmitter;
const domain = require("domain");
const emitterExplicit = new EventEmitter();
// Create a firstDomain for explicit binding
const firstDomain = domain.create();
firstDomain.on('error', function(err) {
console.log("This error will be handled by
using firstDomain ("+err.message+")");
});
// Explicit binding using add method
firstDomain.add(emitterExplicit);
emitterExplicit.on('error',function(err) {
console.log("This error will be handled by
using listener ("+err.message+")");
});
emitterExplicit.emit('error',new Error('listener will handle'));
emitterExplicit.removeAllListeners('error');
emitterExplicit.emit('error',new Error('firstDomain will handle'));
// Create secondDomain for implicit binding
const secondDomain = domain.create();
secondDomain.on('error', function(err) {
console.log("This error will be handled by
using secondDomain ("+err.message+")");
});
// Implicit binding using run method
secondDomain.run(function() {
const emitterImplicit = new EventEmitter();
emitterImplicit.emit('error',new Error('secondDomain
will handle'));
});
firstDomain.remove(emitterExplicit);
emitterExplicit.emit('error', new Error('Exception error
message. The system may crash!'));
运行应用程序的步骤: 将以下代码写入终端以运行服务器:
node index.js
输出:
示例2: 使用显式绑定方法创建服务器。您可以为HTTP服务器使用一个域,也可以为每个请求使用一个单独的域,req和res也在serverUsingDomain的作用域中创建。然而,最好先为每个请求创建一个单独的域,然后将req和res添加到该域中。
const domain = require('domain');
const http = require('http');
const serverUsingDomain = domain.create();
serverUsingDomain.run(() => {
http.createServer((req, res) => {
/* The server is created in the scope of
serverUsingDomain. Req, and res is also
created in the scope of serverUsingDomain.
However, it's a good idea to first create
a separate domain for each request and
then add req and res to it. */
const reqdomain = domain.create();
reqdomain.add(req);
reqdomain.add(res);
reqdomain.on('error', (error) => {
console.error('Error', error, req.url);
try {
res.writeHead(500).end('Some Error occurred.');
} catch (error2) {
console.error('Error is sending 500', error2, req.url);
}
});
}).listen(5000, () => {
console.log("Server is running on PORT 5000");
});
});
运行应用程序的步骤: 在终端中编写以下代码以运行服务器:
node index.js
输出:
Domain 模块中可用的方法: 让我们来看一下 Node.js 中 domain 模块中可用的一些方法。
- domain.create(): 它返回一个 domain 对象。Domain 类封装了活动 domain 对象的路由错误和未捕获异常的功能。
- domain.add(emitter): 它显式地将一个 emitter 添加到 domain 中。如果 emitter 的事件处理函数抛出错误,或者 emitter 发出一个“error”事件,它将被派发到该 domain 的“error”事件,类似于隐式绑定。
- domain.run(function): 在 domain 上下文中执行所提供的函数,并隐式地绑定事件发射器、计时器和在该上下文中创建的低级请求。您可以选择传递参数给该函数。
- domain.bind(callback): 返回的函数是提供的回调函数的一个包装器。当调用返回的函数时,所有抛出的错误都会传播到该 domain 的“error”事件。
- domain.intercept(callback): 该方法类似于 domain.bind(callback)。然而,它不仅捕捉到发生的错误,还捕捉到作为函数的第一个参数发送的 Error 对象。
- domain.enter(): enter() 方法被 run()、bind() 和 intercept() 方法使用来设置活动的 domain。将 domain.active 和 process.domain 设置为该 domain,并隐式地将该 domain 推入由 domain 模块管理的 domain 栈中(有关 domain 栈的更多信息,请参阅 domain.exit())。调用 enter() 将 domain 绑定的异步调用与 I/O 操作链的起始分离开来。 ****
- domain.exit(): exit() 方法退出当前 domain 并将其从 domain 栈中移除。
- domain.remove(emitter): 它是 domain.add(emitter) 的反向操作。从指定的 emitter 中移除 domain 处理。