Why does this callback with a timeout fails to return?

function one(num, callback) {
  return callback(num);
};

function two(num) {
  // return num + 99; << this works
  setTimeout(function() { return num + 99; }, 1000); // << this doesn't
};

console.log(one(55, two));

The result of return within a setTimeout is undefined. I can kinda see why it's happening but I don't know how to avoid it.

I've got some functions that I'm requireing in node.js, and I want to pass a redis object to them to fetch/set some data, which will likely replicate this scenario if I end up using callbacks of some sort.

Is there a way to return that value?

It is the internals of setTimeout() that is calling your anonymous function function() { return num + 99; } and thus the return value from that function goes inside of setTimeout() where it is ignored.

The two() function does not have a return value, so when one() returns the return value from calling two(), that return value is undefined.

Notice in here that there is no return value inside the two() function body:

function two(num) {
  // return num + 99; << this works
  setTimeout(function() { return num + 99; }, 1000); // << this doesn't
};

The return statement inside the anonymous callback passed to setTimeout() executes some time later after two() has finished execution so it has nothing to do with the return value from two().

So it sounds like you understand what is happening, but are just not clear on how to deal with it?

You know that two cannot return. And it becomes clear that if two cannot return, then one cannot return either.

So all that is left to do is embrace it, and be asynchronous all the way down the stack:

function one(num, doWork, callback) {
  doWork(num, callback);
};

function two(num, callback) {
  setTimeout(function() { callback(num + 99); }, 1000);
};

one(55, two, function (result) { console.log(result); });

So return becomes callback all the way down. Notice how many Node APIs take the form:

action(args, function (errorMessage, successMessage) {});

Even when they are synchronous. This lets them work easily with the asynchronous APIs.

There are other cool patterns to help you deal with this when it gets cumbersome. I really like promises for when asynchronous stuff starts getting crazy:

https://github.com/kriskowal/q