Node.js Error Handling Patterns Demystified (with examples)

Alex 👨🏼‍💻FullStack.Cafe - Jul 19 '18 - - Dev Community

Node.js Error Handling Demystified

Error handling in an asynchronous language works in a unique way and presents many challenges, some unexpected. There are seven main error handling patterns in Node.js. Let's briefly check them all.

Originally published on FullStack.Cafe - Never Fail Your Tech Interview Again

Error return value

Simplest pattern that doesn't work asynchronously. Consider:

var validateObject = function (obj) {
    if (typeof obj !== 'object') {
        return new Error('Invalid object');
    }
};

Error throwing

Well-establish pattern, in which a function does its thing and if an error situation arises, it simply bails out throwing an error. Can leave you in an unstable state. It requires extra work to catch them. Also wrapping the async calls in try/catch won't help because the errors happen asynchronously. To fix this, we need domains. Domains provide an asynchronous try...catch.

var validateObject = function (obj) {
    if (typeof obj !== 'object') {
        throw new Error('Invalid object');
    }
};

try {
    validateObject('123');
}
catch (err) {
    console.log('Thrown: ' + err.message);
}

Error callback

Returning an error via a callback is the most common error handling pattern in Node.js. Handling error callbacks can become a mess (callback hell or the pyramid of doom).

var validateObject = function (obj, callback) {
    if (typeof obj !== 'object') {
        return callback(new Error('Invalid object'));
    }
    return callback();
};

validateObject('123', function (err) {
    console.log('Callback: ' + err.message);
});

Error emitting

When emitting errors, the errors are broadcast to any interested subscribers and handled within the same process tick, in the order subscribed.

var Events = require('events');
var emitter = new Events.EventEmitter();

var validateObject = function (a) {
    if (typeof a !== 'object') {
        emitter.emit('error', new Error('Invalid object'));
    }
};

emitter.on('error', function (err) {
    console.log('Emitted: ' + err.message);
});

validateObject('123');

Promises

Promises used for async error handling. Consider:

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

Try...catch with async/await

ES7 Async/await allows us as developers to write asynchronous JS code that look synchronous.

async function f() {

  try {
    let response = await fetch('http://no-such-url');
  } catch(err) {
    alert(err); // TypeError: failed to fetch
  }
}

f();

Await-to-js lib

The variation on async/await without try-catch blocks in Javascript. Consider:

import to from 'await-to-js';

async function main(callback) {
    const [err,quote] = await to(getQuote());
    if(err || !quote) return callback(new Error('No Quote found');
    callback(null,quote);
}

🔗Source: gist.github.com

Thanks 🙌 for reading and good luck on your interview!
Check more FullStack Interview Questions & Answers on 👉 www.fullstack.cafe

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .