Skip to content

Instantly share code, notes, and snippets.

@brianleroux
Created July 17, 2014 20:44
Show Gist options
  • Save brianleroux/713d9bd39a9bda4db106 to your computer and use it in GitHub Desktop.
Save brianleroux/713d9bd39a9bda4db106 to your computer and use it in GitHub Desktop.
demonstrates refactoring a bunch of node style callbacks with async
/* setup a pile of nodejs style methods that accept nodejs style callbacks (where err is the first argument and data the second)*/
var obj = {msg:'before'}
function first(obj, cb) {
console.log('first', obj.msg)
obj.msg += ' ... first'
cb(null, obj)
}
function second(obj, cb) {
console.log('second', obj.msg)
obj.msg += ' ... second'
cb(null, obj)
}
function third(obj, cb) {
console.log('third', obj.msg)
obj.msg += ' ... third'
cb(null, obj)
}
/** this is probably ok but smells terrible and encouraging a likely bad maintenance path
* (just one more cb is no big deal..., next thing you know your 20 deep
*
*
*/
first(obj, function(err, d) {
second(d, function(err, data2) {
third(data2, function(err, data3) {
console.log('final callback', data3)
})
})
})
console.log('\n')
/**
* lets clean this up w/ async, making it easier to add flat functions than nested ones
*/
var async = require('async')
var obj = {msg:'before'}
async.series([
function(next) {
first(obj, next)
},
function(next) {
second(obj, next)
},
function(next) {
third(obj, next)
}],
function(results) {
console.log('final callback again', obj)})
console.log('\n')
/**
* we can do even better still, removing that boilerplate continuation passing style with async.apply
*/
var obj = {msg:'before'}
// lets test the failure condition aborting on the second callback
function fail(obj, cb) {
cb(new Error('omg'))
}
async.series([
async.apply(first, obj),
async.apply(fail, obj),
async.apply(third, obj)
],
function(err) {
console.log('final callback again', err, obj)
})
/**
* but this is still very hadcoded and has a lot of boilerplate machinery
* lets distill the functionality of calling a series of methods, with an object as the first argument and a callback as the second, finally aborting if an error is passed
*/
function series(methods, obj, cb) {
var m = methods.map(function(method) {
return async.apply(method, obj)
})
async.series(m, function(err) { cb(err, obj)})
}
// the final iteration
//
// - flat and easy to reason about
// - easy to add and remove steps
// - traps errors
//
series([first, second, third], obj, function(err, d) {
console.log('final final final', err, d)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment