Nodejs обработка ошибок

Материал из support.qbpro.ru

источник

Safely "throwing" errors

deally we'd like to avoid uncaught errors as much as possible, as such, instead of literally throwing the error, we can instead safely "throw" the error using one of the following methods depending on our code architecture:

For synchronous code

For synchronous code, if an error happens, return the error:

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

For callback-based (ie. asynchronous) code

For callback-based (ie. asynchronous) code, the first argument of the callback is err, if an error happens err is the error, if an error doesn't happen then err is null. Any other arguments follow the err argument:

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

For eventful code

For eventful code, where the error may happen anywhere, instead of throwing the error, fire the error event instead:

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


Safely "catching" errors

Sometimes though, there may still be code that throws an error somewhere which can lead to an uncaught exception and a potential crash of our application if we don't catch it safely. Depending on our code architecture we can use one of the following methods to catch it:

When we know where the error is occurring, we can wrap that section in a 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;
});

If we know where the error is occurring is synchronous code, and for whatever reason can't use domains (perhaps old version of node), we can use the try catch statement:

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

However, there may still be a case where an uncaught error happens in a place that wasn't wrapped in a domain or a try catch statement, in which case to make our application not crash we can use the uncaughtException listener (however doing so can put the application in an unknown state):

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