Alex C. Alex C. - 21 days ago 6
Javascript Question

Check if a function is using a callback or returning a value

In some libraries/frameworks documentations, it tells you that you can use synchronous or asynchronous function.

For example, in Mongoose documentation it says:


Custom validators can also be asynchronous. If your validator function takes 2 arguments, mongoose will assume the 2nd argument is a callback.


So basically when you define a function like this:

function(a){
return false;
}


Mongoose will consider it as synchronous, but we define it like this:

function(a,callback){
setTimeout(function(){
callback(false);
},5000)
}


It will be taken as asynchronous code.

I've noticed the same thing with Mocha testing framework, in the documentation is says:


Testing asynchronous code with Mocha could not be simpler! Simply invoke the callback when your test is complete. By adding a callback (usually named done) to it(), Mocha will know that it should wait for this function to be called to complete the test.





My question is: How do they do this? How would you know when calling a function whether it takes 1 or 2 arguments?

Answer

You'd just check the arguments

function something(arg1, arg2) {
    if (typeof arg2 === 'function') {
        console.log(arg1 + ' has callback');
    } else {
        console.log(arg1 + ' does not have callback');
    }
}

something('call 1');

something('call 2', function() {});

To check how many arguments a function is expecting, you'd use Function.length

length is a property of a function object, and indicates how many arguments the function expects, i.e. the number of formal parameters. This number excludes the rest parameter and only includes parameters before the first one with a default value. By contrast, arguments.length is local to a function and provides the number of arguments actually passed to the function.

console.log((function()        {}).length); /* 0 */
console.log((function(a)       {}).length); /* 1 */
console.log((function(a, b)    {}).length); /* 2 etc. */