Error Handling In Node/Javascript Sucks. Unless You Know this. 2018

Brian Schardt
Frontend Weekly
Published in
3 min readJan 17, 2018

There are so many opinions on Node.js/Javascript as a language, some are fair criticisms, some are lazy programmers not looking for solutions. However, most agree that the aspects of Node that make you bang your head against a wall are callback hell, and promise catching. With the advent of the much needed Node 8, a solution was born, with the ES7 Async/await syntax. Well.. not completely. But if you use the method this article recommends, the node nightmares go away, I promise. The beauty and ease of this method is borrowed from Google’s language Golang, props to them for getting it right the first time.

First I’ll start with the well known problem of callback hell

Messy right? Yeah this is what a bad programmer’s room looks like. This mess makes it nearly impossible to maintain code and manage a readable flow of events.

function Task1() {     
FuncA(function(err, resultA){
if(err) return cb(err);
FuncB(function(err, resultB){
if(err) return cb(err);
FuncC(function(err, resultC){
if(err) return cb(err);
});
});
});
}

ES6. The solution was to build a Promise based system. Where instead of having callbacks now you can write you code in a sudo synchronous way with promise chaining.

function Task1() {   
FuncA.then(FuncB)
.then(FuncC)
.then(FuncD)
.then(data => cb(null, data)
.catch(err => cb(err));
}

This is better.. I guess.. But what if you have errors in one of the Promises chains? The other promises will still execute and there is no clean way to capture them and handle them. The error will follow all the way up the promise chain and you will have no clue where the error occurred.

Async Await to the Rescue

This allows you to write code in a much more synchronous way with all the advantages of async code.

async function Task() {  

const user = await UserModel.findById(1);
if(!user) return ‘no user found’

const savedTask = await TaskModel({userId: user.id, name: 'Demo Task'});
if(user.notificationsEnabled) {
await NotificationService.sendNotification(user.id, 'Task Created');
}
if(savedTask.assignedUser.id !== user.id) {
await NotificationService.sendNotification(savedTask.assignedUser.id, 'Task was created for you');
}

return savedTask;
}

This is so much better than any of the other methods of programming in javascript. However, it is missing something! Something very important. What about error handling! Once an application gets to be a moderate size error handling is insanely important.

Without it it becomes the biggest headache to debug your code. Especially, if you are a developer who inherited a project. Since there is no elegant solution to handling promises most developers just don’t do it. Tried catching promises thats another bad dream when things get complicated. The result? Unhandled Promise Rejections! The most annoying about not handling these rejections is it does not tell us where the error is! Us node/javascript developers know this all too well, it is a nightmare.

Solution: Bad Dreams Gone

The code speaks for itself.

let saveUser = async function(){
let err, user;
[err, user] = await to(UserModel.findById(1));
if(err) TE(err.message, true);
user.name = “this rocks”[err, user] = await to(user.save());
if(err) TE(‘error on saving user’);
return user;
}
//*** HELPER FUNCTIONS ***
//*** npm install parse-error
pe = require('parse-error');
to = function(promise) {
return promise
.then(data => {
return [null, data];
}).catch(err =>
[pe(err)]
);
}
TE = function(err_message, log){ // TE stands for Throw Error
if(log === true){
console.error(err_message);
}
throw new Error(err_message);
}

This code is a million times better to program with. It is super easy to read and uses some of the best practices that other new languages like Golang have adopted. I had a love-hate relationship with node. Now its just love.

The parsed error module helps parse the error message to make it easy to throw custom errors. You can also console.log them to see what lines and row they are on and track the stack. The parsed error module is not necessary but it just helps when an application reaches a certain size.

I promise i’m not a shameless advertiser! I started a company dedicated to using best practices in Node. If you have any questions or want to request any tutorials please comment or message me. We are in Orange County, CA. called Orange Technology.

**This is an improved upon method from the one found: http://blog.grossman.io/how-to-write-async-await-without-try-catch-blocks-in-javascript/

— Brian Alois

--

--