一起读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.domain
The domain that first handled the error.第一次处理error的domain对象error.domain_emitter
The event emitter that emitted an 'error' event with the error object.发出error事件的对象.error.domain_bound
The callback function which was bound to the domain, and passed an error as its first argument.绑定到domain上的callback,callback的第一个参数需要指定为error.error.domain_thrown
A 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.
通过显示绑定就有可能实现.
例如:
Domain 返回一个新的domain对象.Class:Domain
domain类封装了路由error和uncaught 异常到基于的domain中. domain类是EventEmitter的一个子类,如果想要处理domain捕获的错误信息,可以监听error事件.domain.run(fn)
fn
Function 在domain的上下文中运行提供的function,隐式绑定所有的事件触发器,定时器,和在domain上下文中创建的低级的requests. 这是使用domain最基本的一种方式. 例子: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也不会在和他们有深层次的交流.