知识共享许可协议
本作品采用知识共享署名-非商业性使用 3.0 未本地化版本许可协议进行许可。

Node.js v0.10.18 手册 & 文档


#

稳定度: 2 - 不稳定

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.

Domains 提供了一种方式,即以一个单一的组的形式来处理多个不同的IO操作。如果任何一个注册到domain的事件触发器或回调触发了一个‘error’事件,或者抛出一个错误,那么domain对象将会被通知到。而不是直接让这个错误的上下文从`process.on('uncaughtException')'处理程序中丢失掉,也不会致使程序因为这个错误伴随着错误码立即退出。

警告: 不要忽视错误!#

Domain error handlers are not a substitute for closing down your process when an error occurs.

Domain error处理程序不是一个在错误发生时,关闭你的进程的替代品

By the very nature of how throw works in JavaScript, there is almost never any way to safely "pick up where you left off", without leaking references, or creating some other sort of undefined brittle state.

基于'抛出(throw)'在JavaScript中工作的方式,几乎从来没有任何方式能够在‘不泄露引用,不造成一些其他种类的未定义的脆弱状态’的前提下,安全的“从你离开的地方重新拾起(pick up where you left off)”,

The safest way to respond to a thrown error is to shut down the process. Of course, in a normal web server, you might have many connections open, and it is not reasonable to abruptly shut those down because an error was triggered by someone else.

响应一个被抛出错误的最安全方式就是关闭进程。当然,在一个正常的Web服务器中,你可能会有很多活跃的连接。由于其他触发的错误你去突然关闭这些连接是不合理。

The better approach is 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.

更好的方法是发送错误响应给那个触发错误的请求,在保证其他人正常完成工作时,停止监听那个触发错误的人的新请求。

In this way, domain usage goes hand-in-hand with the cluster module, since the master process can fork a new worker when a worker encounters an error. For node 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:

举例来说,以下就不是一个好想法:

var d = require('domain').create(); d.on('error', function(er) { // 这个错误不会导致进程崩溃,但是情况会更糟糕! // 虽然我们阻止了进程突然重启动,但是我们已经发生了资源泄露 // 这种事情的发生会让我们发疯。 // 不如调用 process.on('uncaughtException')! console.log('error, but oh well', er.message); }); d.run(function() { require('http').createServer(function(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.

通过对域的上下文的使用,以及将我们的程序分隔成多个工作进程的反射,我们可以做出更加恰当的反应和更加安全的处理。

```javascript
// 好一些的做法!

var cluster = require('cluster');
var PORT = +process.env.PORT || 1337;

var cluster = require('cluster');
var PORT = +process.env.PORT || 1337;

if (cluster.isMaster) {
  // In real life, you'd probably use more than just 2 workers,
  // and perhaps not put the master and worker in the same file.
  //
  // You can also of course get a bit fancier about logging, and
  // implement whatever custom logic you need to prevent DoS
  // attacks and other bad behavior.
  //
  // See the options in the cluster documentation.
  //
  // The important thing is that the master does very little,
  // increasing our resilience to unexpected errors.

if (cluster.isMaster) {
  // 在工作环境中,你可能会使用到不止一个工作分支
  // 而且可能不会把主干和分支放在同一个文件中
  //
  //你当然可以通过日志进行猜测,并且对你需要防止的DoS攻击等不良行为实施自定义的逻辑
  //
  // 看集群文件的选项
  //
  // 最重要的是主干非常小,增加了我们抵抗以外错误的可能性。

  cluster.fork();
  cluster.fork();

  cluster.fork();
  cluster.fork();

  cluster.on('disconnect', function(worker) {
    console.error('disconnect!');
    cluster.fork();
  });

  cluster.on('disconnect', function(worker) {
    console.error('disconnect!');
    cluster.fork();
  });

} else {
  // the worker
  //
  // This is where we put our bugs!

} else {
  // 工作进程
  //
  // 这是我们出错的地方

  var domain = require('domain');

  var domain = require('domain');

  // See the cluster documentation for more details about using
  // worker processes to serve requests.  How it works, caveats, etc.

  //看集群文件对于使用工作进程处理请求的更多细节,它是如何工作的,它的警告等等。

  var server = require('http').createServer(function(req, res) {
    var d = domain.create();
    d.on('error', function(er) {
      console.error('error', er.stack);

  var server = require('http').createServer(function(req, res) {
    var d = domain.create();
    d.on('error', function(er) {
      console.error('error', er.stack);

    // 因为req和res在这个域存在之前就被创建,
    // 所以我们需要显式添加它们。
    // 详见下面关于显式和隐式绑定的解释。
    d.add(req);
    d.add(res);

    // Now run the handler function in the domain.
    d.run(function() {
      handleRequest(req, res);
    });
  });
  server.listen(PORT);
}

    // 现在在域里面运行处理器函数。
    d.run(function() {
      handleRequest(req, res);
    });
  });
  server.listen(PORT);
}

    // 这个部分不是很重要。只是一个简单的路由例子。
    // 你会想把你的超级给力的应用逻辑放在这里。
    function handleRequest(req, res) {
      switch(req.url) {
        case '/error':
          // 我们干了一些异步的东西,然后。。。
          setTimeout(function() {
            // 呃。。。
            flerb.bark();
          });
          break;
        default:
          res.end('ok');
      }
    }

对Error(错误)对象的内容添加#

Any time an Error object is routed through a domain, a few extra fields are added to it.

每一次一个Error对象被导向经过一个域,它会添加几个新的字段。

  • error.domain The domain that first handled the error.
  • error.domainEmitter The event emitter that emitted an 'error' event with the error object.
  • error.domainBound The callback function which was bound to the domain, and passed an error as its first argument.
  • error.domainThrown A boolean indicating whether the error was thrown, emitted, or passed to a bound callback function.

  • error.domain 第一个处理这个错误的域。

  • error.domainEmitter 用这个错误对象触发'error'事件的事件分发器。
  • error.domainBound 回调函数,该回调函数被绑定到域,并且一个错误会作为第一参数传递给这个回调函数。
  • error.domainThrown 一个布尔值表明这个错误是否被抛出,分发或者传递给一个绑定的回调函数。

隐式绑定#

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.

如果多个域正在被使用,那么所有的EventEmitter对象(包括Stream对象,请求,应答等等)会被隐式绑定到它们被创建时的有效域。

Additionally, callbacks passed to lowlevel 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.

而且,被传递到低层事件分发请求的回调函数(例如fs.open,或者其它接受回调函数的函数)会自动绑定到有效域。如果这些回调函数抛出错误,那么这个域会捕捉到这个错误。

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对象自己不会作为有效域的子对象被隐式添加到有效域。因为如果这样做的话,会很容易影响到请求和应答对象的正常垃圾回收。

If you want to nest Domain objects as children of a parent Domain, then you must explicitly add them.

如果你在一个父Domain对象里嵌套子Domain对象,那么你需要显式地添加它们。

Implicit binding routes thrown errors and 'error' events to the Domain's error event, but does not register the EventEmitter on the Domain, so domain.dispose() will not shut down the EventEmitter. Implicit binding only takes care of thrown errors and 'error' events.

隐式绑定将被抛出的错误和'error'事件导向到Domain对象的error事件,但不会注册到Domain对象上的EventEmitter对象,所以domain.dispose()不会令EventEmitter对象停止运作。隐式绑定只关心被抛出的错误和 'error'事件。

显式绑定#

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.

有时,正在使用的域并不是某个事件分发器所应属的域。又或者,事件分发器在一个域内被创建,但是应该被绑定到另一个域。

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.

例如,对于一个HTTP服务器,可以有一个正在使用的域,但我们可能希望对每一个请求使用一个不同的域。

That is possible via explicit binding.

这可以通过显示绑定来达到。

For example:

例如:

serverDomain.run(function() {
  // 服务器在serverDomain的作用域内被创建
  http.createServer(function(req, res) {
    // req和res同样在serverDomain的作用域内被创建
    // 但是,我们想对于每一个请求使用一个不一样的域。
    // 所以我们首先创建一个域,然后将req和res添加到这个域上。
    var reqd = domain.create();
    reqd.add(req);
    reqd.add(res);
    reqd.on('error', function(er) {
      console.error('Error', er, req.url);
      try {
        res.writeHead(500);
        res.end('Error occurred, sorry.');
      } catch (er) {
        console.error('Error sending 500', er, req.url);
      }
    });
  }).listen(1337);    
});
```

domain.create()#

  • return: Domain

  • return: Domain

Returns a new Domain object.

返回一个新的Domain对象。

类: Domain#

The Domain class encapsulates the functionality of routing errors and uncaught exceptions to the active Domain object.

Domain类封装了将错误和没有被捕捉的异常导向到有效对象的功能。

Domain is a child class of EventEmitter. To handle the errors that it catches, listen to its error event.

Domain是 EventEmitter类的一个子类。监听它的error事件来处理它捕捉到的错误。

domain.run(fn)#

  • fn Function

  • fn Function

Run the supplied function in the context of the domain, implicitly binding all event emitters, timers, and lowlevel requests that are created in that context.

在域的上下文里运行提供的函数,隐式地绑定所有该上下文里创建的事件分发器,计时器和低层请求。

This is the most basic way to use a domain.

这是使用一个域的最基本的方式。

Example:

示例:

var d = domain.create();
d.on('error', function(er) {
  console.error('Caught error!', er);
});
d.run(function() {
  process.nextTick(function() {
    setTimeout(function() { // 模拟几个不同的异步的东西
      fs.open('non-existent file', 'r', function(er, fd) {
        if (er) throw er;
        // 继续。。。
      });
    }, 100);
  });
});

In this example, the d.on('error') handler will be triggered, rather than crashing the program.

在这个例子里, d.on('error') 处理器会被触发,而不是导致程序崩溃。

domain.members#

  • Array

  • Array

An array of timers and event emitters that have been explicitly added to the domain.

一个数组,里面的元素是被显式添加到域里的计时器和事件分发器。

domain.add(emitter)#

  • emitter EventEmitter | Timer emitter or timer to be added to the domain

  • emitter EventEmitter | Timer 被添加到域里的时间分发器或计时器

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.

显式地将一个分发器添加到域。如果这个分发器调用的任意一个事件处理器抛出一个错误,或是这个分发器分发了一个error事,那么它会被导向到这个域的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.

这对于从setIntervalsetTimeout返回的计时器同样适用。如果这些计时器的回调函数抛出错误,它将会被这个域的error处理器捕捉到。

If the Timer or EventEmitter was already bound to a domain, it is removed from that one, and bound to this one instead.

如果这个Timer或EventEmitter对象已经被绑定到另外一个域,那么它将会从那个域被移除,然后绑定到当前的域。

domain.remove(emitter)#

  • emitter EventEmitter | Timer emitter or timer to be removed from the domain

  • emitter EventEmitter | Timer 要从域里被移除的分发器或计时器

The opposite of domain.add(emitter). Removes domain handling from the specified emitter.

domain.add(emitter)函数恰恰相反,这个函数将域处理从指明的分发器里移除。

domain.bind(callback)#

  • callback Function The callback function
  • return: Function The bound function

  • callback Function 回调函数

  • return: Function 被绑定的函数

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.

返回的函数会是一个对于所提供的回调函数的包装函数。当这个被返回的函数被调用时,所有被抛出的错误都会被导向到这个域的error事件。

例子#

d.on('error', function(er) {
  // 有个地方发生了一个错误。
  // 如果我们现在抛出这个错误,它会让整个程序崩溃
  // 并给出行号和栈信息。
});

domain.intercept(callback)#

  • callback Function The callback function
  • return: Function The intercepted function

  • callback Function 回调函数

  • return: Function 被拦截的函数

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.

这个函数与domain.bind(callback)几乎一模一样。但是,除了捕捉被抛出的错误外,它还会拦截作为第一参数被传递到这个函数的Error对象。

In this way, the common if (er) return callback(er); pattern can be replaced with a single error handler in a single place.

在这种方式下,常见的'if(er) return callback(er);'的方式可以被一个单独地方的单独的错误处理所取代。

例子#

d.on('error', function(er) {
  // 有个地方发生了一个错误。
  // 如果我们现在抛出这个错误,它会让整个程序崩溃
  // 并给出行号和栈信息。
});

domain.enter()#

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函数对于runbindintercept来说就像它们的管道系统:它们使用enter函数来设置有效域。enter函数对于域设定了domain.activeprocess.domain ,还隐式地将域推入了由域模块管理的域栈(关于域栈的细节详见domain.exit())。enter函数的调用,分隔了异步调用链以及绑定到一个域的I/O操作的结束或中断。

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.

调用enter仅仅改变活动的域,而不改变域本身。 Enterexit在一个单独的域可以被调用任意多次。

If the domain on which enter is called has been disposed, enter will return without setting the domain.

如果域的enter已经设置,enter将不设置域就返回。

domain.exit()#

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函数退出当前的域,将当前域从域的栈里移除。每当当程序的执行流程准要切换到一个不同的异步调用链的上下文时,要保证退出当前的域。exit函数的调用,分隔了异步调用链以及绑定到一个域的I/O操作的结束或中断。

If there are multiple, nested domains bound to the current execution context, exit will exit any domains nested within this domain.

如果有多个嵌套的域绑定到当前的执行上下文, 退出将退出在这个域里的所有的嵌套。

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.

调用exit只会改变有效域,而不会改变域自身。在一个单一域上,Enterexit可以被调用任意次。

If the domain on which exit is called has been disposed, exit will return without exiting the domain.

如果在这个域名下exit 已经被设置,exit 将不退出域返回。

domain.dispose()#

稳定度: 0 - 已过时。请通过设置在域上的错误事件处理器,显式地东失败的IO操作中恢复。

Once dispose has been called, the domain will no longer be used by callbacks bound into the domain via run, bind, or intercept, and a dispose event is emitted.

一旦dispose被调用,通过runbindintercept绑定到这个域的回调函数将不再使用这个域,并且一个dispose事件会被分发。