Created
September 18, 2012 13:41
-
-
Save spion/3743154 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The original function. Nothing wrong with it. Its short and simple. | |
// The code flow is obvious. | |
function myfunction(response) { | |
db.stuff(function stuff_cb (results) { | |
var transformed = trans(results); | |
db.stuffWith(transformed, function stuffWith_cb(endResult) { | |
var finalTransform = final(endResult, transformed); | |
response.end(finalTransform); | |
}); | |
}); | |
} | |
// Naming your callbacks to keep nesting shallow, problem #1 | |
function myfunction(response) { | |
db.stuff(stuff_cb); | |
function stuff_cb(results) { | |
var transformed = trans(results); | |
db.stuffWith(transformed, stuffWith_cb); | |
} | |
function stuffWith_cb(endResult) { | |
var finalTransform = final(endResult, /* where is my transformed? */); | |
response.end(finalTransform); | |
} | |
} | |
// and ugly solution (well, it only really gets ugly after several of these. | |
function myfunction(response) { | |
db.stuff(stuff_cb); | |
var transformed; | |
function stuff_cb(results) { | |
transformed = trans(results); | |
db.stuffWith(transformed, stuffWith_cb); | |
} | |
function stuffWith_cb(endResult) { | |
var finalTransform = final(endResult, transformed); | |
response.end(finalTransform); | |
} | |
} | |
// Lets try async.waterfall. Since its meant for deep nesting, lets add some serious nesting: | |
function myfunction(response) { | |
db.stuff1(function stuff1_cb(result1) { | |
var transformed1 = trans1(result1); | |
db.stuff2(transformed1, function stuff2_cb(result2) { | |
var transformed2 = trans2(result2); | |
db.stuff3(transformed2, function stuff3_cb(result3) { | |
var transformed3 = trans3(result3); | |
db.stuff4(transformed3, function stuff4_cb(result4) { | |
var transformed4 = trans4(result3); | |
db.stuff4(transformed4, function stuff5_cb(result5) { | |
var finalTransform = final(result5, result2, transformed2, transformed1); | |
response.end(finalTransform); | |
}); | |
}); | |
}); | |
}); | |
}); | |
} | |
// Solution #2: async.waterfall. Since waterfall is really meant for deeper nesting... | |
// lets make the original real deep. | |
function myfunction(response) { | |
db.stuff1(function stuff1_cb(result1) { | |
var transformed1 = trans1(result1); | |
db.stuff2(transformed1, function stuff2_cb(result2) { | |
var transformed2 = trans2(result2); | |
db.stuff3(transformed2, function stuff3_cb(result3) { | |
var transformed3 = trans3(result3); | |
db.stuff4(transformed3, function stuff4_cb(result4) { | |
var transformed4 = trans4(result4); | |
db.stuff5(transformed4, function stuff5_cb(result5) { | |
var finalTransform = final(result5, result2, transformed2, transformed1); | |
response.end(finalTransform); | |
}); | |
}); | |
}); | |
}); | |
}); | |
} | |
// And here it is in async.waterfall. | |
function myfunction(response) { | |
async.waterfall([ | |
function (callback) { | |
db.stuff1(function (result1) { | |
var transformed1 = trans1(result1); | |
callback(null, transformed1); | |
}); | |
}, | |
function (transformed1, callback) { | |
db.stuff2(transformed1, function (result2) { | |
var transformed2 = trans2(result2); | |
callback(null, transformed2); | |
}) | |
}, | |
function (transformed2, callback) { | |
db.stuff3(transformed2, function (result3) { | |
var transformed3 = trans3(result3); | |
callback(null, transformed3); | |
}) | |
}, | |
function (transformed3, callback) { | |
db.stuff4(transformed3, function (result4) { | |
var transformed4 = trans4(result4); | |
callback(null, transformed4); | |
}) | |
}], function (err, transformed4) { | |
db.stuff5(transformed4, function (result5) { | |
var finalTransform = final(result5, /* where is my result 2 */ , | |
/* where is my transformed2 */ , /* where is my transformed1 */ ); | |
response.end(finalTransform); | |
}) | |
}); | |
} | |
// Oops, we need to pass those other variables too. No more free-ride closures. | |
function myfunction(response) { | |
async.waterfall([ | |
function (callback) { | |
db.stuff1(function (result1) { | |
var transformed1 = trans1(result1); | |
callback(null, transformed1); | |
}); | |
}, | |
function (transformed1, callback) { | |
db.stuff2(transformed1, function (result2) { | |
var transformed2 = trans2(result2); | |
callback(null, result2, transformed1, transformed2); | |
}) | |
}, | |
function (result2, transformed1, transformed2, callback) { | |
db.stuff3(transformed2, function (result3) { | |
var transformed3 = trans3(result3); | |
callback(null, result2, transformed1, transformed2, transformed3); | |
}) | |
}, | |
function (result2, transformed1, transformed2, transformed3, callback) { | |
db.stuff4(transformed3, function (result4) { | |
var transformed4 = trans4(result4); | |
callback(null, result2, transformed1, transformed2, transformed4); | |
}) | |
}], function (err, result2, transformed1, transformed2, transformed4) { | |
db.stuff5(transformed4, function (result5) { | |
var finalTransform = final(result5, result2, transformed2, transformed1); | |
response.end(finalTransform); | |
}) | |
}); | |
} | |
// I had to pass some of them 5 times. So at the end, we really are back at square one: defining them in the outer scope. | |
function myfunction(response) { | |
var transformed1, result2_outer, transformed2; | |
async.waterfall([ | |
function (callback) { | |
db.stuff1(function (result1) { | |
transformed1 = trans1(result1); | |
callback(null, transformed1); | |
}); | |
}, | |
function (transformed1, callback) { | |
db.stuff2(transformed1, function (result2) { | |
result2_outer = result2; | |
transformed2 = trans2(result2); | |
callback(null, transformed2); | |
}) | |
}, | |
function (transformed2, callback) { | |
db.stuff3(transformed2, function (result3) { | |
var transformed3 = trans3(result3); | |
callback(null, transformed3); | |
}) | |
}, | |
function (transformed3, callback) { | |
db.stuff4(transformed3, function (result4) { | |
var transformed4 = trans4(result4); | |
callback(null, transformed4); | |
}) | |
}], function (err, transformed4) { | |
db.stuff5(transformed4, function (result5) { | |
var finalTransform = final(result5, result2_outer, transformed2, transformed1); | |
response.end(finalTransform); | |
}) | |
}); | |
} | |
// Naming your callbacks to keep nesting shallow, problem #2 | |
function myfunction(response) { | |
// ... | |
// other code | |
// ... | |
db.stuff(stuff_cb); | |
function stuff_cb(results) { | |
var transformed = trans(results); | |
db.stuffWith(transformed, stuffWith_cb); | |
} | |
// LOL MY CAT ADDED CODE HERE because it wasn't obvius | |
// that these functions flow one after another. | |
// And now its even less obvious. | |
function stuffWith_cb(endResult) { | |
var finalTransform = final(endResult, /* where is my transformed? */); | |
response.end(finalTransform); | |
} | |
} | |
// problem #2 solution: none except discipline and being careful not to break flows. | |
// conclusion: nesting is okay. a couple of tabs are comparatively a small price to pay. |
function myfunction(response) {
async.waterfall([
transform.bind(db, 'stuff1', trans1)
transform.bind(db, 'stuff2', trans2)
transform.bind(db, 'stuff3', trans3)
transform.bind(db, 'stuff4', trans4)
], function (data1, x1, data2, x2, data3, x3, data4, x4) {
db.stuff4(x4, function stuff5_cb(data5) {
response.end(final(data5, data2, x2, x1));
});
});
}
function transform(name, xform) {
var args = [].slice.call(arguments, 2);
var fn = args.pop();
var self = this;
function finish(result) {
return fn.apply(self, [null].concat(args).concat([result, xform(result)]));
}
if (args.length) {
var data = args.pop();
return this[name](data, finish);
}
else {
return this[name](data, finish);
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
function myfunction(response) {
async.waterfall([
transform.bind(db, 'stuff1', trans1)
transform.bind(db, 'stuff2', trans2)
transform.bind(db, 'stuff3', trans3)
transform.bind(db, 'stuff4', trans4)
], function (data1, x1, data2, x2, data3, x3, data4, x4) {
db.stuff4(x4, function stuff5_cb(data5) {
response.end(final(data5, data2, x2, x1));
});
});
}
//
// Doing same darn thing over and over when nesting, helper describes this atrocity
//
function transform(name, xform) {
var args = [].slice.call(arguments, 2);
var fn = args.pop();
var self = this;
function finish(result) {
return fn.apply(self, [null].concat(args).concat([result, xform(result)]));
}
if (args.length) {
var data = args.pop();
return this[name](data, finish);
}
else {
return this[name](data, finish);
}
}