web-dev-qa-db-ja.com

Node.jsベストプラクティス例外処理

数日前にnode.jsを試してみました。私は自分のプログラムで未処理の例外があるときはいつでもNodeが終了することに気づきました。これは、私が未処理の例外が発生したときにワーカースレッドだけが死に、コンテナーが要求を受け取ることができる場所に公開されていた通常のサーバーコンテナーとは異なります。これはいくつか質問を投げかけます:

  • process.on('uncaughtException')はそれを防ぐ唯一の効果的な方法ですか?
  • process.on('uncaughtException')は、非同期プロセスの実行中にも未処理の例外をキャッチしますか?
  • キャッチされていない例外が発生した場合に利用できるモジュール(電子メールの送信やファイルへの書き込みなど)は既に構築されていますか?

Node.jsでキャッチされていない例外を処理するための一般的なベストプラクティスを教えてくれるポインタ/記事をいただければ幸いです

710
momo

更新:Joyentは 彼ら自身のガイド を持っています。以下の情報はより要約です。

安全に「スロー」エラー

文字通りエラーをスローするのではなく、可能な限りキャッチされないエラーを回避したいのであれば、コードアーキテクチャに応じて次のいずれかの方法を使用して安全にエラーを「スロー」できます。

  • 同期コードの場合、エラーが発生した場合はエラーを返します。

    // Define divider as a syncrhonous function
    var divideSync = function(x,y) {
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by returning it
            return new Error("Can't divide by zero")
        }
        else {
            // no error occured, continue on
            return x/y
        }
    }
    
    // Divide 4/2
    var result = divideSync(4,2)
    // did an error occur?
    if ( result instanceof Error ) {
        // handle the error safely
        console.log('4/2=err', result)
    }
    else {
        // no error occured, continue on
        console.log('4/2='+result)
    }
    
    // Divide 4/0
    result = divideSync(4,0)
    // did an error occur?
    if ( result instanceof Error ) {
        // handle the error safely
        console.log('4/0=err', result)
    }
    else {
        // no error occured, continue on
        console.log('4/0='+result)
    }
    
  • コールバックベースの(すなわち非同期の)コードの場合、コールバックの最初の引数はerrです。エラーが発生した場合はerrはエラーです。エラーが発生しなかった場合はerrnullです。他の引数はerr引数の後に続きます。

    var divide = function(x,y,next) {
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by calling the completion callback
            // with the first argument being the error
            next(new Error("Can't divide by zero"))
        }
        else {
            // no error occured, continue on
            next(null, x/y)
        }
    }
    
    divide(4,2,function(err,result){
        // did an error occur?
        if ( err ) {
            // handle the error safely
            console.log('4/2=err', err)
        }
        else {
            // no error occured, continue on
            console.log('4/2='+result)
        }
    })
    
    divide(4,0,function(err,result){
        // did an error occur?
        if ( err ) {
            // handle the error safely
            console.log('4/0=err', err)
        }
        else {
            // no error occured, continue on
            console.log('4/0='+result)
        }
    })
    
  • エラーをスローする代わりに、エラーがどこでも発生する可能性がある eventful コードの場合は、代わりに errorイベント を起動します。

    // Definite our Divider Event Emitter
    var events = require('events')
    var Divider = function(){
        events.EventEmitter.call(this)
    }
    require('util').inherits(Divider, events.EventEmitter)
    
    // Add the divide function
    Divider.prototype.divide = function(x,y){
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by emitting it
            var err = new Error("Can't divide by zero")
            this.emit('error', err)
        }
        else {
            // no error occured, continue on
            this.emit('divided', x, y, x/y)
        }
    
        // Chain
        return this;
    }
    
    // Create our divider and listen for errors
    var divider = new Divider()
    divider.on('error', function(err){
        // handle the error safely
        console.log(err)
    })
    divider.on('divided', function(x,y,result){
        console.log(x+'/'+y+'='+result)
    })
    
    // Divide
    divider.divide(4,2).divide(4,0)
    

安全に "キャッチ"エラー

しかし、時には、どこかにエラーを投げるコードがまだあるかもしれません。それは、キャッチできない例外と、それを安全にキャッチしないとアプリケーションのクラッシュを引き起こす可能性があるからです。コードアーキテクチャに応じて、次のいずれかの方法でそれを捕捉できます。

  • エラーが発生している場所がわかれば、そのセクションを node.js domain で囲むことができます。

    var d = require('domain').create()
    d.on('error', function(err){
        // handle the error safely
        console.log(err)
    })
    
    // catch the uncaught errors in this asynchronous or synchronous code block
    d.run(function(){
        // the asynchronous or synchronous code that we want to catch thrown errors on
        var err = new Error('example')
        throw err
    })
    
  • エラーが発生している場所が同期コードであり、何らかの理由でドメイン(おそらく古いバージョンのノード)を使用できないことがわかっている場合は、try catchステートメントを使用できます。

    // catch the uncaught errors in this synchronous code block
    // try catch statements only work on synchronous code
    try {
        // the synchronous code that we want to catch thrown errors on
        var err = new Error('example')
        throw err
    } catch (err) {
        // handle the error safely
        console.log(err)
    }
    

    ただし、非同期的にスローされるエラーはキャッチされないため、非同期コードでtry...catchを使用しないように注意してください。

    try {
        setTimeout(function(){
            var err = new Error('example')
            throw err
        }, 1000)
    }
    catch (err) {
        // Example error won't be caught here... crashing our app
        // hence the need for domains
    }
    

    非同期コードと一緒にtry..catchを使用したい場合は、ノード7.4以上を実行しているときにasync/awaitをネイティブに使用して非同期関数を作成できます。

    try...catchに関してもう1つ注意が必要なことは、完了コールバックをtryステートメント内にラップする危険性があることです。

    var divide = function(x,y,next) {
        // if error condition?
        if ( y === 0 ) {
            // "throw" the error safely by calling the completion callback
            // with the first argument being the error
            next(new Error("Can't divide by zero"))
        }
        else {
            // no error occured, continue on
            next(null, x/y)
        }
    }
    
    var continueElsewhere = function(err, result){
            throw new Error('elsewhere has failed')
    }
    
    try {
            divide(4, 2, continueElsewhere)
            // ^ the execution of divide, and the execution of 
            //   continueElsewhere will be inside the try statement
    }
    catch (err) {
            console.log(err.stack)
            // ^ will output the "unexpected" result of: elsewhere has failed
    }
    

    あなたのコードがより複雑になるので、この問題は非常に簡単です。そのため、ドメインを使用するか、(1)非同期コードで例外をキャッチしない(2)不要な実行をキャッチしようとしないようにエラーを返すのが最善です。 JavaScriptの非同期イベントマシンスタイルの代わりに適切なスレッド化を可能にする言語では、これはそれほど問題ではありません。

  • 最後に、ドメインまたはtry catchステートメントで囲まれていない場所で不明なエラーが発生した場合は、uncaughtExceptionリスナーを使用してアプリケーションをクラッシュさせないようにすることができます(ただし、そうすることでアプリケーションを_に置くことができます)。 不明な状態 ):

    // catch the uncaught errors that weren't wrapped in a domain or try catch statement
    // do not use this in modules, but only in applications, as otherwise we could have multiple of these bound
    process.on('uncaughtException', function(err) {
        // handle the error safely
        console.log(err)
    })
    
    // the asynchronous or synchronous code that emits the otherwise uncaught error
    var err = new Error('example')
    throw err
    
699
balupton

以下は、このトピックに関するさまざまなソースからの要約とキュレーションで、コード例や選択したブログ投稿からの引用を含みます。ベストプラクティスの完全なリスト ここにあります


Node.JSエラー処理のベストプラクティス


番号1:非同期エラー処理にプロミスを使用する

TL; DR:コールバックスタイルで非同期エラーを処理することは、おそらく最速の地獄(別名Doomのピラミッド)です。コードに与えることができる最高の贈り物は、代わりにtry-catchのような非常にコンパクトで使い慣れたコード構文を提供する評判のよいpromiseライブラリを使用することです

それ以外の場合:Node.JSコールバックスタイル、function(err、response)は、エラー処理とカジュアルなコード、過度のネスト、厄介なコーディングパターン

コード例-good

doWork()
.then(doWork)
.then(doError)
.then(doWork)
.catch(errorHandler)
.then(verify);

アンチパターンのコード例-コールバックスタイルのエラー処理

getData(someParameter, function(err, result){
    if(err != null)
      //do something like calling the given callback function and pass the error
    getMoreData(a, function(err, result){
          if(err != null)
            //do something like calling the given callback function and pass the error
        getMoreData(b, function(c){ 
                getMoreData(d, function(e){ 
                    ...
                });
            });
        });
    });
});

ブログの引用:「約束に問題があります」(ブログpouchdbから、キーワード「Node Promises」で11位)

「…実際、コールバックはさらに厄介なことをします。スタックから私たちを奪います。これは通常プログラミング言語では当たり前のことです。スタックなしでコードを書くことは、ブレーキペダルなしで車を運転することに似ています:あなた約束のすべてのポイントは、非同期になったときに失った言語の基礎を返すことです。 、スロー、スタック。しかし、それらを利用するためにはプロミスを正しく使用する方法を知る必要があります。 "


Number2:組み込みのエラーオブジェクトのみを使用する

TL; DR:エラーを文字列またはカスタムタイプとしてスローするコードを見るのはかなり一般的です。これにより、エラー処理ロジックとモジュール間の相互運用性が複雑になります。 。約束を拒否するか、例外をスローするか、エラーを発行するか-Node.JS組み込みのエラーオブジェクトを使用すると、均一性が向上し、エラー情報の損失を防ぎます

それ以外の場合:いくつかのモジュールを実行するとき、どのタイプのエラーが返ってくるかが不明確であるため、発生する例外について推論して処理するのがはるかに難しくなります。価値があるとしても、カスタムタイプを使用してエラーを記述すると、スタックトレースなどの重要なエラー情報が失われる可能性があります。

コード例-正しく実行する

    //throwing an Error from typical function, whether sync or async
 if(!productToAdd)
 throw new Error("How can I add new product when no value provided?");

//'throwing' an Error from EventEmitter
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));

//'throwing' an Error from a Promise
 return new promise(function (resolve, reject) {
 DAL.getProduct(productToAdd.id).then((existingProduct) =>{
 if(existingProduct != null)
 return reject(new Error("Why fooling us and trying to add an existing product?"));

アンチパターンのコード例

//throwing a String lacks any stack trace information and other important properties
if(!productToAdd)
    throw ("How can I add new product when no value provided?");

ブログの引用:「文字列はエラーではない」(ブログ「devthought」より、キーワード「Node.JSエラーオブジェクト」で6位)

"...エラーの代わりに文字列を渡すと、モジュール間の相互運用性が低下します。instanceofErrorチェックを実行している可能性がある、またはエラーについて詳しく知りたいAPIとの契約を破ります。後で説明するように、エラーオブジェクトには、コンストラクタに渡されるメッセージを保持する以外に、最新のJavaScriptエンジンで非常に興味深いプロパティがあります。」


番号3:操作上のエラーとプログラマーのエラーを区別する

TL; DR:操作エラー(APIが無効な入力を受信したなど)は、エラーの影響が完全に理解され、思慮深く処理できる既知のケースを指します。一方、プログラマーエラー(未定義の変数を読み取ろうとするなど)は、アプリケーションを正常に再起動するように指示する不明なコード障害を指します

それ以外の場合:エラーが表示された場合は常にアプリケーションを再起動できますが、軽微な予測エラー(操作エラー)のために〜5000人のオンラインユーザーを失望させる理由?反対も理想的ではありません。未知の問題(プログラマーエラー)が発生したときにアプリケーションを維持すると、予期しない動作が発生する可能性があります。 2つを区別することで、巧妙に行動し、与えられたコンテキストに基づいてバランスの取れたアプローチを適用できます。

コード例-正しく実行する

    //throwing an Error from typical function, whether sync or async
 if(!productToAdd)
 throw new Error("How can I add new product when no value provided?");

//'throwing' an Error from EventEmitter
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));

//'throwing' an Error from a Promise
 return new promise(function (resolve, reject) {
 DAL.getProduct(productToAdd.id).then((existingProduct) =>{
 if(existingProduct != null)
 return reject(new Error("Why fooling us and trying to add an existing product?"));

コード例-エラーを動作可能(信頼済み)としてマークする

//marking an error object as operational 
var myError = new Error("How can I add new product when no value provided?");
myError.isOperational = true;

//or if you're using some centralized error factory (see other examples at the bullet "Use only the built-in Error object")
function appError(commonType, description, isOperational) {
    Error.call(this);
    Error.captureStackTrace(this);
    this.commonType = commonType;
    this.description = description;
    this.isOperational = isOperational;
};

throw new appError(errorManagement.commonErrors.InvalidInput, "Describe here what happened", true);

//error handling code within middleware
process.on('uncaughtException', function(error) {
    if(!error.isOperational)
        process.exit(1);
});

Blog Quote:「それ以外の場合、あなたは状態を危険にさらします」(ブログのデバッグ可能から、キーワード「Node.JS uncaught exception」でランク3)

…JavaScriptでthrowがどのように機能するかという性質上、参照をリークしたり、未定義のその他の種類を作成したりせずに、「中断した場所をピックアップ」する方法はほとんどありません脆弱な状態。スローされたエラーに応答する最も安全な方法は、プロセスをシャットダウンすることです。もちろん、通常のWebサーバーでは、多くの接続が開かれている可能性があります。エラーが他の誰かによってトリガーされたため、それらを突然シャットダウンします。より良いアプローチは、エラーをトリガーしたリクエストにエラー応答を送信し、他のユーザーを通常の時間で終了させ、そのワーカーで新しいリクエストのリッスンを停止することです」


Number4:ミドルウェア内ではなく一元的にエラーを処理します

TL; DR:管理者へのメールやロギングなどのエラー処理ロジックは、すべてのエンドポイント(Expressミドルウェアなど)である専用の集中オブジェクトにカプセル化する必要があります、cronジョブ、単体テスト)がエラーが発生したときに呼び出します。

それ以外の場合:1つの場所でエラーを処理しないと、コードの重複が発生し、おそらく不適切に処理されるエラーが発生します

コード例-典型的なエラーフロー

//DAL layer, we don't handle errors here
DB.addDocument(newCustomer, (error, result) => {
    if (error)
        throw new Error("Great error explanation comes here", other useful parameters)
});

//API route code, we catch both sync and async errors and forward to the middleware
try {
    customerService.addNew(req.body).then(function (result) {
        res.status(200).json(result);
    }).catch((error) => {
        next(error)
    });
}
catch (error) {
    next(error);
}

//Error handling middleware, we delegate the handling to the centrzlied error handler
app.use(function (err, req, res, next) {
    errorHandler.handleError(err).then((isOperationalError) => {
        if (!isOperationalError)
            next(err);
    });
});

ブログの引用:「より低いレベルでは、呼び出し元にエラーを伝播する以外に有用なことはできない」(ブログJoyentから、キーワードで1位「Node.JSエラー処理」)

「…スタックのいくつかのレベルで同じエラーを処理することになります。これは、エラーを呼び出し元に伝達する以外、エラーを呼び出し元に伝達するなど、下位レベルが何も役に立たない場合に発生します。操作を再試行するか、エラーをユーザーに報告するか、その他の適切な応答が何であるかは、トップレベルの呼び出し元のみが知っています。しかし、それは、すべてのエラーを単一のトップレベルに報告することを意味するわけではありませんそのコールバック自体は、どのコンテキストでエラーが発生したのかを知ることができないためです


Number5:Swaggerを使用したAPIエラーのドキュメント化

TL; DR:API呼び出し元に、どのエラーが返される可能性があるかを知らせて、クラッシュすることなくこれらを慎重に処理できるようにします。これは通常、SwaggerのようなREST AP​​Iドキュメントフレームワークで行われます

それ以外の場合:APIクライアントは、理解できないエラーを受け取ったためにクラッシュして再起動することを決定する場合があります。注:APIの呼び出し元はあなたかもしれません(マイクロサービス環境では非常に一般的です)

ブログの引用:「どのエラーが発生する可能性があるかを発信者に伝える必要があります」(ブログJoyentから、キーワード「Node.JS logging」で1位) )

…エラーの処理方法について説明しましたが、新しい関数を作成するとき、関数を呼び出したコードにエラーをどのように配信しますか? …エラーが発生する可能性がわからない場合、またはエラーの意味がわからない場合は、偶発的な場合を除き、プログラムを修正できません。したがって、新しい関数を作成する場合は、呼び出し元にどのエラーが発生する可能性があり、何を測定するのかを伝える必要があります


番号6:見知らぬ人が町に来たときに、プロセスを正常にシャットダウンする

TL; DR:不明なエラーが発生した場合(開発者エラー、ベストプラクティス#3を参照)-アプリケーションの健全性に不確実性があります。一般的な方法では、ForeverやPM2などの「リスタート」ツールを使用してプロセスを慎重に再起動することをお勧めします

それ以外の場合:なじみのない例外がキャッチされると、一部のオブジェクトが障害状態になる可能性があります(たとえば、グローバルに使用され、もはやイベントを発生させないイベントエミッター何らかの内部障害が発生する可能性があります)、今後のすべてのリクエストが失敗したり、狂ったように動作する可能性があります

コード例-クラッシュするかどうかの決定

//deciding whether to crash when an uncaught exception arrives
//Assuming developers mark known operational errors with error.isOperational=true, read best practice #3
process.on('uncaughtException', function(error) {
 errorManagement.handler.handleError(error);
 if(!errorManagement.handler.isTrustedError(error))
 process.exit(1)
});


//centralized error handler encapsulates error-handling related logic 
function errorHandler(){
 this.handleError = function (error) {
 return logger.logError(err).then(sendMailToAdminIfCritical).then(saveInOpsQueueIfCritical).then(determineIfOperationalError);
 }

 this.isTrustedError = function(error)
 {
 return error.isOperational;
 }

ブログの引用:「エラー処理には3つの考え方があります」(ブログjsrecipesから)

…エラー処理については、主に3つの考え方があります。1.アプリケーションをクラッシュさせて再起動します。 2.考えられるすべてのエラーを処理し、クラッシュすることはありません。 3。 2つの間のバランスの取れたアプローチ


Number7:成熟したロガーを使用してエラーの可視性を高める

TL; DR:Winston、Bunyan、Log4Jなどの成熟したロギングツールのセットは、エラーの検出と理解を高速化します。したがって、console.logを忘れてください。

それ以外の場合:console.logsを介して、またはクエリツールやまともなログビューアを使用せずに手動で乱雑なテキストファイルを介してスキミングすると、遅くまで仕事で忙しくなります

コード例-動作中のWinstonロガー

//your centralized logger object
var logger = new winston.Logger({
 level: 'info',
 transports: [
 new (winston.transports.Console)(),
 new (winston.transports.File)({ filename: 'somefile.log' })
 ]
 });

//custom code somewhere using the logger
logger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });

ブログの引用: "いくつかの要件を特定できます(ロガーの場合):"(ブログstrongblogから)

…いくつかの要件を特定できます(ロガーの場合):1.各ログ行にタイムスタンプを付けます。これはかなり自明です-各ログエントリがいつ発生したかを知ることができるはずです。 2.ロギング形式は、人間だけでなく機械でも簡単に消化できるものでなければなりません。 3.複数の構成可能な宛先ストリームを許可します。たとえば、トレースログを1つのファイルに書き込むが、エラーが発生した場合、同じファイルに書き込み、エラーファイルに書き込み、同時に電子メールを送信する場合があります…


Number8:APM製品を使用してエラーとダウンタイムを発見する

TL; DR:監視およびパフォーマンス製品(別名APM)は、コードベースまたはAPIをプロアクティブに測定し、エラー、クラッシュ、スローな部分を自動的にハイライト表示できるようにしますあなたが行方不明でした

それ以外の場合:APIのパフォーマンスとダウンタイムの測定に多大な労力を費やす可能性があります。これらがUXに与える影響

ブログの引用:「APM製品セグメント」(ブログYoni Goldbergより)

「…APM製品は、3つの主要なセグメントで構成されています。1。WebサイトまたはAPIの監視–HTTPリクエストを介して稼働時間とパフォーマンスを常に監視する外部サービス。 Pingdom、Uptime Robot、New Relic2。コードインストルメンテーション–製品ファミリにエージェントを組み込む必要がある製品ファミリ機能が遅いコード検出、例外統計、パフォーマンスモニタリングなどの機能を活用できるアプリケーションNew Relic、App Dynamics3。オペレーションインテリジェンスダッシュボード–これらの製品ラインは、アプリケーションのパフォーマンスを簡単に把握するのに役立つメトリックとキュレートされたコンテンツで運用チームを促進することに焦点を当てています。これには通常、複数の情報ソース(アプリケーションログ、DBログ、サーバーログなど)そして、ダッシュボードの設計を前もって行います。以下は、Datadog、Splunkの一部の選択候補です。


上記は短縮バージョンです- こちらのベストプラクティスと例を参照

82
Yonatan

あなたはキャッチされていない例外をキャッチすることができますが、それは限られた用途です。 http://debuggable.com/posts/node-js-dealing-with-uncaught-exceptions:4c933d54-1428-443c-928d-4e1ecbdd56cb を参照してください。

monitforeverまたはupstartは、クラッシュしたときにノードプロセスを再起動するために使用できます。グレースフルシャットダウンはあなたが望むことができる最善です(例えば、すべてのインメモリデータをキャッチされていない例外ハンドラに保存する)。

29
nponeccop

nodejs domains は、nodejsのエラーを処理するための最新の方法です。ドメインは、エラーまたは他のイベントと、従来からスローされているオブジェクトの両方をキャプチャできます。ドメインは、インターセプトメソッドを介して最初の引数として渡されたエラーでコールバックを処理するための機能も提供します。

通常のtry/catchスタイルのエラー処理と同様に、エラーが発生したときにエラーをスローし、エラーを他のコードへの影響から分離したい領域をブロックすることが通常最善です。これらの領域を「ブロックアウト」する方法は、分離コードのブロックとしての関数を使用してdomain.runを呼び出すことです。

同期コードでは、上記で十分です。エラーが発生した場合は、エラーをスローするか、キャッチしてそこで処理し、元に戻す必要があるデータを元に戻します。

try {  
  //something
} catch(e) {
  // handle data reversion
  // probably log too
}

非同期コールバックでエラーが発生した場合は、データのロールバック(共有状態、データベースなどの外部データなど)を完全に処理できる必要があります。 ORあなたは、例外が起こったことを示すために何かを設定しなければなりません - そのフラグを気にするところはどこでも、コールバックが完了するのを待たなければなりません。

var err = null;
var d = require('domain').create();
d.on('error', function(e) {
  err = e;
  // any additional error handling
}
d.run(function() { Fiber(function() {
  // do stuff
  var future = somethingAsynchronous();
  // more stuff

  future.wait(); // here we care about the error
  if(err != null) {
    // handle data reversion
    // probably log too
  }

})});

上記のコードの中には見苦しいものもありますが、見やすくするために自分でパターンを作成することができます。

var specialDomain = specialDomain(function() {
  // do stuff
  var future = somethingAsynchronous();
  // more stuff

  future.wait(); // here we care about the error
  if(specialDomain.error()) {
    // handle data reversion
    // probably log too
  } 
}, function() { // "catch"
  // any additional error handling
});

UPDATE(2013-09):

上で、私は fiber semantics を意味する未来を使用します。これはあなたがインラインで先物を待つことを可能にします。これは実際にあなたがeverythingのために伝統的なtry-catchブロックを使うことを可能にします - それが私が行くための最良の方法であると思います。しかしながら、あなたはいつもこれをすることができるわけではありません(すなわち、ブラウザで)...

ファイバーのセマンティクスを必要としない先物もあります(これは通常のブラウザのJavaScriptで動作します)。これらは先物、約束、または据え置きと呼ばれることができます(私はこれから先に先に言及するつもりです)。普通のJavaScriptの先物ライブラリでは、先物間でエラーを伝播させることができます。これらのライブラリのうちのいくつかだけが、スローされた未来が正しく処理されるのを可能にするので、注意してください。

例:

returnsAFuture().then(function() {
  console.log('1')
  return doSomething() // also returns a future

}).then(function() {
  console.log('2')
  throw Error("oops an error was thrown")

}).then(function() {
  console.log('3')

}).catch(function(exception) {
  console.log('handler')
  // handle the exception
}).done()

これは、ピースが非同期であっても、通常のtry-catchを模倣しています。それは印刷されます:

1
2
handler

このフローを中断する例外がスローされたため、 '3'は表示されません。

ブルーバードの約束を見てください。

スローされた例外を適切に処理する、これら以外の他の多くのライブラリは見つかっていません。たとえば、jQueryの延期はしないでください。「失敗」ハンドラが例外を「then」ハンドラにスローすることは決してありません。

15
B T

私は最近これについて http://snmaynard.com/2012/12/21/node-error-handling/ で書きました。バージョン0.8のnodeの新機能はドメインであり、これを使うとすべての形式のエラー処理を1つの管理しやすい形式にまとめることができます。あなたは私の記事でそれらについて読むことができます。

また、 Bugsnag のようなものを使用して、キャッチされていない例外を追跡し、Eメール、チャットルーム、またはキャッチされていない例外について作成されたチケットを受け取ることができます(私はBugsnagの共同創設者です)。

11
Simon Maynard

Try-catchを使用することが適切な場合の1つの例は、forEachループを使用する場合です。これは同期的ですが、同時に内部スコープでreturn文を使用することはできません。代わりに、try and catchアプローチを使用して、適切なスコープ内のErrorオブジェクトを返すことができます。検討してください:

function processArray() {
    try { 
       [1, 2, 3].forEach(function() { throw new Error('exception'); }); 
    } catch (e) { 
       return e; 
    }
}

それは上記の@ baluptonによって記述されたアプローチの組み合わせです。

4

Step.jsライブラリ を追加したいと思います/ /常に次のstep関数に渡すことで、例外を処理することができます。したがって、最後のステップとして、前のステップのいずれかでエラーがないかをチェックする機能を持つことができます。このアプローチはあなたのエラー処理を大いに単純化することができます。

以下はgithubページからの引用です。

スローされた例外はすべてキャッチされ、最初の引数として次の関数に渡されます。あなたがコールバック関数をあなたのメイン関数をインラインにネストしていない限り、これは決してキャッチされない例外が存在することを防ぎます。単一のキャッチされていない例外がサーバー全体をダウンさせる可能性があるため、これは長時間実行されているnode.JSサーバーにとって非常に重要です。

さらに、ステップを使用してスクリプトの実行を制御し、最後のステップとしてクリーンアップセクションを作成できます。例えば、もしあなたがNodeでビルドスクリプトを書き、それが書くのにかかった時間を報告したいのであれば、最後のステップはそれをすることができます(最後のコールバックを掘り出すことを試みるよりも)。

3

しばらく前にこの記事を読んだ後、私はそれがAPI /関数レベルで例外処理のためにドメインを使用するのが安全であるかどうか疑問に思いました。私が書いたそれぞれの非同期関数で例外処理コードを単純化するためにそれらを使いたかった。私の関心事は、各機能に新しいドメインを使用すると、かなりのオーバーヘッドが発生することです。私の宿題は、最小限のオーバーヘッドがあることと、パフォーマンスがドメインによっては実際には状況によってはtry catchよりも優れていることを示しているようです。

http://www.lighthouselogic.com/#/using-a-new-domain-for-each-async-function-in-node/ /

2
Sudsy

ここではエラーを検出する方法について非常によく説明しましたが、エラーをどこかにログアウトして、エラーを表示して問題を解決できるようにすることを忘れないでください。

BunyanはNodeJSのためのポピュラーなロギングフレームワークです - それはあなたがconsole.logを避けている限り、ローカルデバッグのためにそれを有用にするたくさんの異なる出力場所に書き出すことを支持します。ドメインのエラーハンドラで、エラーをログファイルに書き出すことができます。

var log = bunyan.createLogger({
  name: 'myapp',
  streams: [
    {
      level: 'error',
      path: '/var/tmp/myapp-error.log'  // log ERROR to this file
    }
  ]
});

チェックするエラーやサーバーが多数ある場合、これは時間がかかることがあるので、Raygun(免責事項、私はRaygunで働いています)のようなツールを調べると、エラーをまとめることができます。あなたがツールとしてRaygunを使うことに決めたならば、セットアップもとても簡単です。

var raygunClient = new raygun.Client().init({ apiKey: 'your API key' });
raygunClient.send(theError);

PM2や永遠のようなツールを使用してクロスした場合、アプリはクラッシュし、発生したことをログアウトして、大きな問題なく再起動できるはずです。

1
K. Craven
1
Cap