node.js Domain 時代のエラー処理のコーディングパターン

來源:互聯網
上載者:User

id:kazuhooku さんの記事 node.js におけるエラー処理のコーディングパターン (もしくは非同期 JavaScript における例外処理。
ナイスです! なんと素晴らしいタイミングでのブログでしょうか!

「東京Node學園 5時限目」で id:koichik さんのプレゼンで node-v0.7.8 から isaacs 版 Domain が導入されるという発表がありましたが、予定通り昨日 Domain 機能付きの node-v0.7.8 がリリースされました。

しかもDomain のドキュメント付きです。 http://nodejs.org/docs/v0.7.8/api/domain.html

ちょうど id:kazuhooku さんの記事の例は node.js の新機能 Domain を教科書通りに適応するとどうなるのか紹介するのにぴったりのお題なので
Node.js v0.8 の新機能 Domain の使い方
について書かせていただきます。

Node.jsの新機能 Domain を使う

まずドメインを利用してエラー処理するには

  • domain モジュールの require()
  • domain オブジェクトの產生
  • domain で受けるエラーリスナーの登録
  • domain とエラーハンドリングとの結び付け
    • eventEmitter の場合は Domain.add
    • 関數の場合は Domain.bind

といった段取りが必要です。
id:kazuhooku さんの記事にあるコードを、Domain 使ったらどのようなコーディングパターンが考えられるかいくつ例示してみたいと思います。。(註:動作には node-v0.7.8 以降が必要です。)

今回3つのパターンで考えました。

  • パターン1: コールバック関數にドメインを結びつけてエラーハンドリングを行う
  • パターン2: 関數呼び出し時にドメインを結びつけてエラーハンドリングを行う
  • パターン3: 関數定義時にドメインを結びつけてエラーハンドリングを行う

ではサンプルコードとともにドメインを使ったコーディングパターンを例示していきます。

パターン1: コールバック関數にドメインを結びつける方法

まずはエラーオブジェクトを含むコールバックでドメインとエラーを結びつける場合です。

// domain_sample1.jsvar domain = require('domain');var fs = require('fs');var d = domain.create();function countChars(filename, callback) {  // コールバックに直接ドメインをバインド  fs.readFile(filename, 'utf-8', d.bind(function(err, data) {    if (err) throw err;    callback(data.length);  }));}function main(args) {  countChars(args[0], function(length) {    console.log(length);  });}d.on('error', function(err) {  console.log(err.message);});main(process.argv.slice(2))
unixjp:~/tmp/github/node> ./node domain_sample1.js hogeENOENT, open 'hoge'

はい、きれいなコードになりましたね。

パターン2: 関數呼び出しに時にドメインを結びつける方法

関數を呼び出すときにバインドしたい場合は、

// domain_sample2.jsvar fs = require('fs');var domain = require('domain');var d = domain.create();function countChars(filename, callback) {  fs.readFile(filename, 'utf-8', function(err, data) {    if (err) throw err;    callback(data.length);  });}function main(args) {  // 関數を呼び出す時にドメインをバインドする。  (d.bind(countChars))(args[0], function(length) {    console.log(length);  });}d.on('error', function(err) {  console.log(err.message);});main(process.argv.slice(2));

な感じです。

パターン3: 関數定義にドメインを結びつける方法

関數定義直後にバインドするなら、

// domain_sample3.jsvar fs = require('fs');var domain = require('domain');var d = domain.create();function countChars(filename, callback) {  fs.readFile(filename, 'utf-8', function(err, data) {    if (err) throw err;    callback(data.length);  });}// 関數定義直後にドメインにバインドcountChars = d.bind(countChars);function main(args) {  countChars(args[0], function(length) {    console.log(length);  });}d.on('error', function(err) {  console.log(err.message);});main(process.argv.slice(2));

といったようになります。

まとめ

他には event.EventEmitter のエラーと結び付けたい場合は Domain.bind() ではなく Domain.add() すればドメイン內のエラー処理で扱えます。
このように Domain の機能を使うとこれまでと違った形でエラーハンドリングをする可能性が広がり、従來より可読性の高く・簡潔なコードが書けるようになるでしょう。

追記: Domain.intercept() を使う

id:koichik さんからのコメントにあるよう domain.bind(cb, true) だと throw しなくてもエラーをひっかけてくれます。(呼ばれる関數の第一引數が Error インスタンスであることが條件ですけど) これをまとめて domain.intercept() という関數になってます。
ということで domain.intercept() を使うともっとすっきりに書けます。

// domain_sample4.jsvar domain = require('domain');var fs = require('fs');var d = domain.create();function countChars(filename, callback) {  fs.readFile(filename, 'utf-8', d.intercept(function(err, data) {    callback(data.length);  }));}function main(args) {  countChars(args[0], function(length) {    console.log(length);  });}d.on('error', function(err) {  console.log(err.message);});main(process.argv.slice(2));
unixjp:~/tmp/github/node> ./node domain_sample4.js hogeENOENT, open 'hoge'

ありがとうございます。 > id:koichik さん。

追記の追記: Domain.run() を使う。

またまた id:koichik さんから twitter 経由で Domain.run() の使い方を教えていただきました。(実はマニュアルには記載されていませんけど)→ id:koichik さんからのコメントで public API としてドキュメント化されました。https://github.com/joyent/node/commit/c0a9985da7a7d3f6ebc51805d6955d92b1bd6e78
これを使うと上記パターン2(関數呼び出しに時にドメインを結びつける方法)のコードで (d.bind(fn))(args) と書いていたところが d.run(function() {fn(args)} と書けて、もっとすっきりします。

// domain_sample5.jsvar fs = require('fs');var domain = require('domain');var d = domain.create();function countChars(filename, callback) {  fs.readFile(filename, 'utf-8', function(err, data) {    if (err) throw err;    callback(data.length);  });}function main(args) {  // 関數を呼び出す時にドメインをバインドする。  d.run(function() {    countChars(args[0], function(length) {      console.log(length);    });  });}d.on('error', function(err) {  console.log(err.message);});main(process.argv.slice(2));

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.