Anderson Green
Anderson Green

Reputation: 31810

Determine whether a method is synchronous or asynchronous

In node.js, is it possible to determine (using a function) whether a method is synchronous or asynchronous?

I'd like to write a function that does the following:

function isSynchonous(methodName) {
    //if the method is synchronous, return true. Otherwise, return false.
}

Upvotes: 20

Views: 9856

Answers (4)

Redu
Redu

Reputation: 26161

Why exactly do you need to know, is the real question.

Having said that; that's possible with the new JS abstractions. Nowadays for the async functions those explicitly defined by a preceding async keyword you can perform a test like;

async function test(){}
var type = Object.getPrototypeOf(test).constructor.name;
console.log(type); // <- 'AsyncFunction'

cool..!

As for the normal functions those happen to return a promise, we must remember that it's just a sync function returning a promise object right away, synchronously. That means you have to check dynamically if a function returns a promise in advance, before invoking the function. I think that takes you to a type level programming adventure which exists in sophisticated languages like Haskell etc.

Upvotes: 2

gx0r
gx0r

Reputation: 5471

You don't necessarily know. A function could even be randomly synchronous or asynchronous.

For example, a function that takes another function could execute that function immediately, or it could schedule to execute it at a later time using setImmediate or nextTick. The function could even randomly choose to call its passed function synchronously or asynchronous, such as:

console.log('Start')

function maybeSynchOrAsync(fun) {

  var rand = Math.floor((Math.random() * 2))

  if (rand == 0) {
    console.log('Executing passed function synchronously')
    fun()
    console.log('Done.')
  } else {
    console.log('Executing passed function asynchronously via setImmediate')
    setImmediate(fun)
    console.log('Done.')
  }
}

maybeSynchOrAsync(function () { console.log('The passed function has executed.') });

Further, technically speaking, every function call is synchronous. If you call a function F, and F queues a callback function to be invoked later (using setTimeout or whatever mechanism), the original function F still has a synchronous return value (whether it's undefined, a promise, a thunk, or whatever).

Upvotes: 5

djechlin
djechlin

Reputation: 60788

From a language standpoint this is not possible, which I believe llambda's answer proves.

  • Functions can do things asynchronously but return something synchronously; say, return the number of async tasks that were fired off.
  • Functions can synchronously return promises... that represent asynchronous information. I would call such a method asynchronous but the language can't really tell that.
  • In some perverse sense every asynchronous function "returns" something... undefined if nothing else.

From an engineering standpoint:

  • read the documentation.
  • If the function accepts a callback, it is likely asynchronous. Look at the function signature.
  • Read the code.
  • Use "common sense." If the function does IO and returns a result from IO it must be, in some case, asynchronous. This includes file reading, reading from standard input, saving to a database, and HTTP/AJAX requests. Note streams are often used for this, which represents an asynchronous task, but the callbacks are special.

Furthermore there are functions that mix the two.

function(callback) {
    if(ready) {
        callback();
    }
    else {
        setTimeout(callback, 5000);
    }
}

Arguably this is very evil, and correct practice would be

if(ready) {
    process.nextTick(callback);
}

so the function has uniform behavior.

However there is a hacky way to tell if anything asynchronous happened, at least in Node.js. See this discussion.

// untested!! please read the documentation on these functions before using yourself
var work = process._getActiveHandles().length + process._getActiveCallbacks().length;
foo;
var newWork = (process._getActiveHandles().length + process._getActiveCallbacks().length) - work;
if(newWork > 0) {
    console.log("asynchronous work took place.");
}

This works because asynchronous work cannot resolve on the same tick, by definition, and because Node.js is single threaded.

Upvotes: 8

Ry-
Ry-

Reputation: 224952

No, that's impossible. The methods aren't just marked synchronous or asynchronous, they either use callbacks or they don't.

Upvotes: 3

Related Questions