-
-
Save darscan/962548 to your computer and use it in GitHub Desktop.
Function.prototype.or = function(callback) { | |
var next = this; | |
return function(err, doc) { | |
if (err) { | |
callback(err, doc); | |
} else { | |
next(doc, callback); | |
} | |
}; | |
}; |
Sure, so Node.js is all about "non-blocking" calls for I/O. This means lots of callbacks. The community has settled on the following approach to callbacks:
function someCallback(err, result) {
if (err) {
// handle the error
} else {
// handle the result
}
};
Async function signatures look something like this:
function someFunction(val, callback);
You call it and pass a callback. When it finishes it calls the callback. Unfortunately, when you need to do a bunch of asynchronous things in sequence things become really, really messy:
someFunction("hello", function(err, result) {
if (err) {
// handle error
} else {
var param = result.someValue;
someOtherFunction(param, function(err, result) {
if (err) {
// handle error
} else {
theThirdAsyncFunction(500, function(err, result) {
if (err) {
// handle error
} else {
console.log(result);
}
});
}
});
}
});
Of course, we can blame the nested anonymous functions and refactor thusly:
someFunction("hello", handleSomefunction);
function handleSomefunction(err, result) {
if (err) {
// handle error
} else {
var param = result.someValue;
someOtherFunction(param, handleSomeOtherFunction);
}
};
function handleSomeOtherFunction(err, result) {
if (err) {
// handle error
} else {
theThirdAsyncFunction(500, handleTheThirdAsyncFunction);
}
};
function handleTheThirdAsyncFunction(err, result) {
if (err) {
// handle error
} else {
console.log(result);
}
};
But what if we don't want to handle errors at every step? Could we chain it up and have any error terminate the flow and be handled elsewhere? Also, notice that our functions are callbacks, not methods (they describe what they handle rather than what they do).
The code in my gist creates callback functions to wrap async methods:
// This is where I want to handle the eventual result or error
function handler(err, result) {
if (err) throw err;
console.log(result);
};
// Kick it off
doSomeFunction("hello", handler);
function doSomeFunction(val, callback) {
someFunction(val, doSomeOtherFunction.or(callback));
};
function doSomeOtherFunction(val, callback) {
var param = val.someValue;
someOtherFunction(param, doTheThirdFunction.or(callback));
};
function doTheThirdFunction(val, callback) {
theThirdAsyncFunction(500, callback);
};
Now the functions are all aync functions rather than callback functions, and the error and final result are handled in one place.
There are tons and tons of flow-control libraries out there (in fact, writing your own is a right of passage in the Node world). This was a light weight solution that worked pretty well for my needs.
Nice one, thanks!
You should take a look at Spidernode in combination with task.js: Seamless async functions chaining using generators. See slides 37 to 39 of this presentation for details.
Thanks Till! I'd come across task.js, but not Spidernode. Will bookmark for future reference.
Interesting... care to explain?