node package manager


DRY error handling

Outcome.js is a simple flow-control library which wraps your .callback(err, result) functions.

  • Write less code for handling errors.
  • Easier to maintain.
  • Keep error handling code separate.

Here's the traditional method of handling errors:

var fs = require('fs');
function doSomething(pathcallback) {
fs.realpath(path, onRealPath);
function onRealPath(errpath) {
if(err) return callback(err);
fs.lstat(path, onStat);
function onStat(errstats) {
if(err) return callback(err);
callback(err, stats);
doSomething('/path/to/something', function(errresult) {
//inline with result handling - yuck 
if(err) {
//do something with error 
//do something with result 

The outcome.js way:

var fs  = require('fs'),
outcome = require('outcome');
function doSomething(pathcallback) {
//wrap the callback around an error handler so any errors in *this* function 
//bubble back up to the callback - I'm lazy and I don't wanna write this stuff... 
var on = outcome.error(callback);
//on success, call onRealPath. Any errors caught will be sent back 
fs.realpath(path, on.success(onRealPath));
function onRealPath(path) {
//ONLY call onStat if we've successfuly grabbed the file stats 
fs.lstat(path, on.success(onStat));
function onStat(stats) {
//no errors, so send a response back 
callback(null, stats);
var on = outcome.error(function(error) {
//do something with error 
doSomething('/path/to/something', on.success(function(response) {
//do something with result 
  • listeners - Object of listeners you want to attach to outcome.
var onResult = outcome({
//called when an error is caught 
errorfunction(error) {
//called when an error is NOT present 
successfunction(resultthirdParam) {
//called back when an error, or result is present 
callbackfunction(errresultthirdParam) {

As shown in the example above, you can also wrap-around an existing callback:

var onResult = outcome.error(function(error) {
success(function(resultthirdParam) {
callback(function(errorresultthirdParam) {

By default, any unhandled errors are thrown. To get around this, you'll need to listen for an unhandledError:

outcome.on('unhandledError', function(error) {
//report bugs here..., then throw again. 
fs.stat('s'+__filename, outcome.success(function() {

Called when on error/success. Same as function(err, data) { }

Here's a redundant example:

fs.stat(__filename, outcome.error(function(err) {
//handle error 
}).success(function(data) {
//handle result 
}.callback(function(errresult) {
//called on fn complete regardless if there's an error, or success 

Called on Success.

var onOutcome = outcome.success(function(dataanotherParamandAnotherParam) {
//handle success data 
onOutcome(null, "success!", "more data!", "more results..");

Called on error.

var onOutcome = outcome.error(function(err) {
onOutcome(new Error("something went wrong...")); 

Custom response handler

outcome.handle(function(response) {
if(response.errors) this.error(response);
if( this.success(response);
outcome = require "outcome"
doSomething(path, callback) ->
on = outcome.error callback
# first get the realpath 
fs.realpath pathon.success onRealPath
# on real path, get stats 
onRealPath(path) -> fs.lstat pathon.success onStat
# on stat, finish 
onStat(stats) -> callback nullstats
# call do something 
doSomething '/path/to/something'outcome 
success: (statis) ->
# do something 
error: (error) ->
# do something else 

Calling .error(), .success(), .callback() generates a new function which copies the previous listeners. Checkout fs-test in the examples folder.