多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

中國最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2

nodejs教程

Node.js

閱讀 (2276)

穩定性: 2 - 不穩定

域提供了一種方法,它能把多個不同的 IO 操作看成一個單獨組。如果任何一個注冊到域的事件或者回調觸發 error 事件,或者拋出一個異常,域就會接收到通知,而不是在process.on('uncaughtException')處理函數一樣丟失錯誤的上下文,也不會使程序立即退出。

警告:不要忽視錯誤!

域錯誤處理程序并不是一個錯誤發生時關閉你的進程的替代品。

基于 JavaScript 中拋出異常的工作原理,基本上不可能在不泄露引用,或者不造成一些其他未定義的狀態下,完全重現現場。

響應拋出錯誤最安全的方法就是關閉進程。一個正常的服務器會可能有很多活躍的連接,因為某個錯誤就關閉所有連接顯然是不合理的。

比較好的方法是給觸發錯誤的請求發送回應,讓其他連接正常工作時,停止監聽觸發錯誤的人的新請求。

按這種方法,和集群(cluster)模塊可以協同工作,當某個進程遇到錯誤時,主進程可以復制一個新的進程。對于 Node 程序,終端代理或者注冊的服務,可以留意錯誤并做出反應。

舉例來說,下面的代碼就不是好辦法:

javascript
// XXX WARNING!  BAD IDEA!

var d = require('domain').create();
d.on('error', function(er) {
  // The error won't crash the process, but what it does is worse!
  // Though we've prevented abrupt process restarting, we are leaking
  // resources like crazy if this ever happens.
  // This is no better than 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);
});

通過使用域的上下文,并將程序切為多個工作進程,我們能夠更合理的響應,處理錯誤更安全。

javascript
// 好一些的做法!

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.

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

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

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

  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);

      // Note: 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
        var killtimer = setTimeout(function() {
          process.exit(1);
        }, 30000);
        // But don't keep the process open just for that!
        killtimer.unref();

        // stop taking new requests.
        server.close();

        // Let the master know we're dead.  This will trigger a
        // 'disconnect' in the cluster master, 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(function() {
      handleRequest(req, res);
    });
  });
  server.listen(PORT);
}

// This part isn't important.  Just an example routing thing.
// You'd put your fancy application logic here.
function handleRequest(req, res) {
  switch(req.url) {
    case '/error':
      // We do some async stuff, and then...
      setTimeout(function() {
        // Whoops!
        flerb.bark();
      });
      break;
    default:
      res.end('ok');
  }
}

錯誤對象的附加內容

任何時候一個錯誤被路由傳到一個域的時,會添加幾個字段。

  • error.domain 第一個處理錯誤的域
  • error.domainEmitter 用這個錯誤對象觸發 'error' 事件的事件分發器
  • error.domainBound 綁定到 domain 的回調函數,第一個參數是 error。
  • error.domainThrown boolean 值,表明是拋出錯誤,分發,或者傳遞給綁定的回到函數。

隱式綁定

如果域正在使用中,所有新分發的對象(包括 流對象,請求,響應等)將會隱式的綁定到這個域。

另外,傳遞給底層事件循環(比如 fs.open 或其他接收回調的方法)的回調函數將會自動的綁定到這個域。如果他們拋出異常,域會捕捉到錯誤信息。

為了避免過度使用內存,域對象不會象隱式的添加為有效域的子對象。如果這樣做的話,很容易影響到請求和響應對象的垃圾回收。

如果你想將域對象作為子對象嵌入到父域里,就必須顯式的添加它們。

隱式綁定路由拋出的錯誤和 'error' 事件,但是不會注冊事件分發器到域,所以 domain.dispose() 不會關閉事件分發器。隱式綁定僅需注意拋出的錯誤和 'error' 事件。

顯式綁定

有時候正在使用的域并不是某個事件分發器的域。或者說,事件分發器可能在某個域里創建,但是被綁定到另外一個域里。

例如,HTTP 服務器使用正一個域對象,但我們希望可以每一個請求使用一個不同的域。

這可以通過顯式綁定來實現。

例如:

// 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.');
      } catch (er) {
        console.error('Error sending 500', er, req.url);
      }
    });
  }).listen(1337);
});

domain.create()

  • return: {Domain}

返回一個新的域對象。

Class: Domain

這個類封裝了將錯誤和沒有捕捉到的異常到有效對象功能。

域是 EventEmitter 的子類. 監聽它的 error事件來處理捕捉到的錯誤。

domain.run(fn)

  • fn {Function}

在域的上下文運行提供的函數,隱式的綁定了所有的事件分發器,計時器和底層請求。

這是使用域的基本方法。

例如:

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);
  });
});

這個例子里程序不會崩潰,而會觸發d.on('error')

domain.members

  • {Array}

顯式添加到域里的計時器和事件分發器數組。

domain.add(emitter)

  • emitter {EventEmitter | Timer} 添加到域里的計時器和事件分發器

顯式將一個分發器添加到域。如果分發器調用的事件處理函數拋出錯誤,或者分發器遇到 error 事件,將會導向域的 error 事件,和隱式綁定一樣。

對于 setIntervalsetTimeout 返回的計時器同樣適用。如果這些回調函數拋出錯誤,將會被域的 'error' 處理器捕捉到。

如果計時器或分發器已經綁定到域,那它將會從上一個域移除,綁定到當前域。

domain.remove(emitter)

  • emitter {EventEmitter | Timer} 要移除的分發器或計時器

與 domain.add(emitter) 函數恰恰相反,這個函數將分發器移除出域。

domain.bind(callback)

  • callback {Function} 回調函數
  • return: {Function}被綁定的函數

返回的函數是一個對于所提供的回調函數的包裝函數。當調用這個返回的函數被時,所有被拋出的錯誤都會被導向到這個域的 error 事件。

Example

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(callback)

  • callback {Function} 回調函數
  • return: {Function} 被攔截的函數

domain.bind(callback) 類似。除了捕捉被拋出的錯誤外,它還會攔截 Error 對象作為參數傳遞到這個函數。

這種方式下,常見的 if (er) return callback(er); 模式,能被一個地方一個錯誤處理替換。

Example

var d = domain.create();

function readSomeFile(filename, cb) {
  fs.readFile(filename, 'utf8', d.intercept(function(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', 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.enter()

這個函數就像 run, bind, 和 intercept 的管道系統,它設置有效域。它設定了域的domain.active and process.domain,還隱式的將域推到域模塊管理的域棧(關于域棧的細節詳見domain.exit())。enter函數的調用,分隔了異步調用鏈以及綁定到一個域的I/O操作的結束或中斷。

調用enter僅改變活動的域,而不改變域本身。在一個單獨的域里可以調用任意多次Enterexit

domain.exit()

exit 函數退出當前域,并從域的棧里移除。每當程序的執行流程要切換到不同的異步調用鏈的時候,要保證退出當前域。調用 exit 函數,分隔了異步調用鏈,和綁定到一個域的I/O操作的結束或中斷。

如果有多個嵌套的域綁定到當前的上下文,exit 函數將會退出所有嵌套。

調用 exit 僅改變活躍域,不會改變自身域。在一個單獨的域里可以調用任意多次Enterexit

如果在這個域名下 exit 已經被設置,exit 將不退出域返回。

domain.dispose()

穩定性: 0 - 拋棄。通過域里設置的錯誤事件來顯示的消除失敗的 IO 操作。

調用 dispos 后,通過 run,bind 或 intercept 綁定到域的回調函數不再使用這個域,并且分發 dispose 事件。

關閉
程序員人生
主站蜘蛛池模板: 亚洲视频大全 | 美国私人vps一夜爽毛片免费 | 97欧美在线看欧美视频免费 | 叼嘿视频在线观看免费 | freexxx性乌克兰xxx | 一区二区三区欧美视频 | 国产区精品视频 | 性欧美video另类hd高清 | 国产在线不卡一区 | 国产日韩欧美亚洲 | 免费在线公开视频 | 日本aa大片 | 国产精品人成 | 日韩亚洲欧美一区二区三区 | 国产欧美精品专区一区二区 | 亚洲成人福利在线 | 视频一区 国产 | 久久国产精品久久久久久久久久 | 久草午夜视频 | 欧美xx网站| 成人免费淫片免费观看 | 小说区图片区 | 九九精品免视看国产成人 | 中文字幕乱码视频中文字幕14 | 国产成人精品一区二区免费 | 国产精品一区二区三区免费视频 | 交性大片欧美网 | 黄a大片| 一级做a爰片久久毛片潮喷 一级做a爰片久久毛片看看 | 欧美一区二三区 | 亚洲区欧美中文字幕久久 | 久久精品国产69国产精品亚洲 | 亚洲精品亚洲人成毛片不卡 | 网址黄| 欧美三级视频 | 欧美日本在线一区二区三区 | 亚洲天堂视频在线观看免费 | 黑色丝袜高跟国产在线91 | 欧美中文字幕一区 | 色网站综合| 免费亚洲网站 |