On the topic of using callbacks, promises + generators will enable you to do the same job with almost the same level of performance (see http://spion.github.io/posts/why-i-am-switching-to-promises....) whilst avoiding callback hell and having to perform error handling in multiple places.
A good Promise library (like https://github.com/petkaantonov/bluebird) even provides mechanisms for writing functions that both return Promises as well as accept callbacks, allowing your API client to choose how they wish to use it.
Also, beware of making a function "asynchronous" by simply having it accept a callback parameter, e.g.:
function myFunc(v, cb) {
someOtherObject.v = v;
cb();
}
myFunc(5, function(err) {
if (err) return console.error(err);
console.log('call done');
});
console.log('call started');
In the above code, you'll see "call done" before you see "call started" because myFunc() isn't really functioning asynchronously.This is yet another reason to use a good Promise library like Bluebird, as it ensures that even if you wrap a synchronous function inside a Promise the resulting execution will flow as if it was asynchronous.