`

一起读nodejs(八)----域(domain)

 
阅读更多

本文是对nodejs0.8.9版本的api开发手册解读.nodejs网址

(Domain)

stability:1 - experimental

域提供了一种简单把多个不同的io操作看作一个单独的组的方法.如果任何一个事件发射器或者已在域中注册的回调函数发出了一个error事件,或者抛出一个error错误信息,域将会被通知,而不是在process.on('caughtException')处理函数一样丢失上下文,或者用一个code引起程序退出.(有点像数据库的事物的样子)

这是在node0.8版本中新增加的特性.这是它第一次亮相,其他它能在未来有更重要的作用.请使用它,并提供使用反馈.

由于它的试验性质,域的特性只有在domain模块加载一次以后才会生效.没有域是默认被创建或者注册的.这是故意设计成这样的,为了避免在现在的程序中产生一些不利的影响.在未来node的版本中期待改成默认启用.


错误对象的补充(additions to Error objects)

任何时候一个error对象被路由传递到一个domain(域看着别扭)中时,需要添加一些额外的字段到error对象上.

  • error.domainThe domain that first handled the error.第一次处理error的domain对象
  • error.domain_emitterThe event emitter that emitted an 'error' event with the error object.发出error事件的对象.
  • error.domain_boundThe callback function which was bound to the domain, and passed an error as its first argument.绑定到domain上的callback,callback的第一个参数需要指定为error.
  • error.domain_thrownA boolean indicating whether the error was thrown, emitted, or passed to a bound callback function.一个boolean对象,指定这个error对象是被抛出的还是发出的,或者传到到domain 绑定的callback中.

 

当一个EventEmitter遇到一个错误时,典型的动作时发出一个error事件.在node里面,error事件将会被作为特殊情况处理,如果没有相应的监听函数,默认的动作是打印堆栈信息,然后退出程序.

当所有的EventEmitter对象在添加新的监听函数时都会发出newListener事件.

 

隐式绑定(Implicit Binding)

如果domain被启用的,那么所有的新的EventEmitter对象(包括:Stream对象,request对象,response对象等等)都将会在他们被创建的时候隐式的绑定到这个激活的domain上.

此外,传递给低级别的事件循环请求(例如:fs.open,或者的callback-taking方法)将会自动的绑定到激活的domain上.如果他们抛出异常,domain会捕获错误信息.

为了避免使用过多的内存,domain对象不会被隐式的添加为当前激活的domain的子对象.如果他们存在,这将不容易阻止request和response对象成为合适的垃圾收集对象.

如果你需要内嵌一个domain对象到一个父domain对象中,你必须明确的添加他们,并且稍后调用dispose()方法(dispose是销毁domain对象,稍后有介绍).

隐式绑定路由跑出错误信息和error事件到domain的error事件中.但是不会在domain对象上注册事件触发器,所以domain.dispose()不会关闭事件触发器.隐式绑定只是处理抛出的错误信息和error事件.


显示绑定(Explicit binding)

有时,domain对象不应该被当成一个指定事件的事件发射器(Emitter)来使用.或者,事件发射器已经在一个domain中的环境变量中被创建,但是应该被绑定到其他domain上.

例如这里有一个http服务器的domain对象,但是我们想在每个request上使用一个单独的domain.

通过显示绑定就有可能实现.

例如:

// create a top-level domain for the server
var serverDomain = domain.create();

serverDomain.run(function() {
  // server is created in the scope of serverDomain
  http.createServer(function(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.
    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.');
        res.on('close', function() {
          // forcibly shut down any other things added to this domain
          reqd.dispose();
        });
      } catch (er) {
        console.error('Error sending 500', er, req.url);
        // tried our best.  clean up anything remaining.
        reqd.dispose();
      }
    });
  }).listen(1337);
});


 

 

domain.create()

 

  • return:Domain
返回一个新的domain对象.

 


 

Class:Domain

domain类封装了路由error和uncaught 异常到基于的domain中.
domain类是EventEmitter的一个子类,如果想要处理domain捕获的错误信息,可以监听error事件.

 


domain.run(fn)

 

  • fnFunction
在domain的上下文中运行提供的function,隐式绑定所有的事件触发器,定时器,和在domain上下文中创建的低级的requests.
这是使用domain最基本的一种方式.
例子:
var d = domain.create();
d.on('error', function(er) {
  console.error('Caught error!', er);
});
d.run(function() {
  process.nextTick(function() {
    setTimeout(function() { // simulating some various async stuff
      fs.open('non-existent file', 'r', function(er, fd) {
        if (er) throw er;
        // proceed...
      });
    }, 100);
  });
});
在这个例子中,do.on('error')处理器将会被触发,而不是程序挂掉.(在不使用domain的情况下,遇见未捕获的异常或者抛出error事件会导致程序死掉.)

domain.members

  • Array
显示绑定到domain中的定时器和事件触发器的数组.

domain.add(emitter)

  • event Emitter|timer Emitter|timer to be added to the domain. 事件触发器或者定时器触发器或者定时器被添加到domain中.
显式的添加一个触发器到domain中.当事件触发器抛出一个错误时任何一个事件处理函数被调用时,或者这个事件触发器发出一个error时,他们都将会被路由到domain的error事件中,就像隐式绑定一样.
当定时器从setInterval或者setTimeout返回时也将这样操作.如果他们的回调函数抛出异常时,将会被domain的error事件处理函数所捕获.
如果定时器或者事件触发器已经绑定到了domain中,node会将他们从原先的domain中移除,并且添加到当前的domain中.

domain.remove(emitter)

  • event Emitter|timer Emitter|timer to be added to the domain. 事件触发器或者定时器触发器或者定时器被从domain中移除.
和domain.add(emitter)相反,这个方法是从指定的触发器上移除domain的处理操作.


domain.bind(cb)

  • cb function 回调函数.
  • return:function,绑定后的函数.
返回的函数,将是一个包裹了所提供的回调函数的函数.当这个返回的函数被调用,抛出的任何错误都将会被路由到domain的error事件中.
var d = domain.create();

function readSomeFile(filename, cb) {
  fs.readFile(filename, 'utf8', d.bind(function(er, data) {
    // if this throws, it will also be passed to the domain
    return cb(er, data ? JSON.parse(data) : null);
  }));
}

d.on('error', function(er) {
  // an error occurred somewhere.
  // if we throw it now, it will crash the program
  // with the normal line number and stack message.
});

domain.intercept(cb)

  • cb function 回调函数.
  • return:function,被拦截的函数.
这个方法几乎和domain.bind(cb)方法一样.然而,除了会捕获抛出的错误信息之外,将会拦截error对象,并当作需要返回的函数的第一个参数.
这样一来,比较常见的:if(er)return cb(er)这种方式就可以被取代,你只需要单独的在一个错误处理handler里面处理所有的error信息了.

例子:

var d = domain.create();

function readSomeFile(filename, cb) {
  fs.readFile(filename, 'utf8', d.intercept(function(data) {
//也就是说只要使用了d.intercept()方法包裹的回调函数,如果他们发生错误或者发出error事件,都会被统一的下面的d.on('error',fn)所处理.这种情况和domain.run的区别是domain.run是需要所有的把所有东西都放在一个domain里面,才能拦截domain的对象的事件.而domain.intercept(),你想包裹哪一个回调函数都行.可以对异常类型进行全局处理.
    // 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', function(er) {
  // an error occurred somewhere.
  // if we throw it now, it will crash the program
  // with the normal line number and stack message.
});



domain.dispose()

dispose方法用来销毁一个domain对象,并且在清空任何一个和所有io和这个domain有关联的对象或事件时,努力做到最好.流(Streams)可以被终止,结束,关闭,并且/或者 销毁.定时器是被清除.显示绑定的回调函数不会在会调用.任何一个从domain中出现的error事件也会被忽略.

调用dispose的意图通常是为了当domain的环境变量被发现在一个错误的状态时避免发生级联错误.

一旦domain被disposed掉,dispose事件将会发出.

注意:io操作可能还会继续执行.然而,为了达到最大限度的可能性,一旦一个domain被disposed,在domain中的发射器集合中产生的或者发出的错误信息将会被忽略.所以,甚至如果一些剩下的动作依然在执行,node也不会在和他们有深层次的交流.

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics