Coming from a background that was not heavy on callbacks, whenever I wanted to short-circuit a method I would simply "return".
For example:
public void Log(string data)
{
if (data == null)
return;
...
}Now, when writing async NodeJS applications, I have a similar tendency to treat the callback as the return, e.g.,
function log(data, callback) {
if (!data) {
callback('error');
}
...
};However, this is incorrect and quickly leads to bugs throughout the code. When the log function is called with a null data arguement, it will indeed call the error callback, but then will continue execution of the function. What is needed is a return statement after the callback, e.g.,
function log(data, callback) {
if (!data) {
callback('error');
return;
}
...
};This will ensure the correct behavior when running the log function. Another approach the NodeJS devs use it to return the callback, e.g.,
function log(data, callback) {
if (!data) {
return callback('error');
}
...
};This approach is nice because it is very explicit. It is more explicit, which can help in the future where some developer might want to add logic in between the error callback being called and the return statement. It is also nice because it reduces the lines of code from 2 to 1. However, there have been performance tests that show it may be slightly less effecient to return a callback versus calling a callback and then returning (http://jsperf.com/return-vs-no-return/4)
An example of a bad guard function in node:
function log(data, callback) {
if (!data) {
callback('error');
}
callback(null);
};Some examples of good guard functions in node:
function log(data, callback) {
if (!data) {
callback('error');
} else {
callback(null);
}
};
function log(data, callback) {
if (!data) {
callback('error');
return;
}
callback(null);
};
function log(data, callback) {
if (!data) {
return callback('error');
}
callback(null);
};For me, the reason to use a return guard in a method vs. using an else statement is that it helps avoid nesting.