20

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.
}
Ry-
  • 218,210
  • 55
  • 464
  • 476
Anderson Green
  • 30,230
  • 67
  • 195
  • 328

4 Answers4

8

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.

Community
  • 1
  • 1
djechlin
  • 59,258
  • 35
  • 162
  • 290
5

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).

gx0r
  • 4,682
  • 2
  • 23
  • 24
3

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

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • 1
    I don't understand why it's impossible. I could try inspecting a method's source code; would that give any indication of whether or not the method was synchronous? – Anderson Green Oct 02 '12 at 00:11
  • Also, is there a clear distinction between "synchronous functions" and "asynchronous functions" in Javascript, or is it possible for a function to be either synchronous and asynchronous in different use cases? – Anderson Green Oct 02 '12 at 00:11
  • 1
    @AndersonGreen: Inspecting a method's source code to determine if it's asynchronous is unfortunately equivalent to solving the halting problem, and isn't meaningful anyway. No, there isn't a clear distinction between synchronous functions and asynchronous functions. The difference is that they may take a callback and call it asynchronously. They may also call it synchronously. There's a mixture of the two - a synchronous operation that calls an asynchronous one. Some functions automatically decide based on the presence of a callback. Asynchronicity isn't a language feature. – Ry- Oct 02 '12 at 14:13
  • note it's argued mixed sync/async is evil. If it's sync it should still happen on `process.nextTick` – djechlin Aug 19 '14 at 17:03
  • @djechlin: That applies for I/O; how about computing a factorial? It depends. – Ry- Aug 20 '14 at 00:09
  • What do you mean? A factorial should sometime return sync and sometimes async? – djechlin Aug 20 '14 at 05:04
  • @djechlin: Well, a factorial can take a long time to compute with the right input; does that mean mixing it with code that uses a callback is bad? – Ry- Aug 20 '14 at 05:06
  • I still don't understand your example, you can of course call a computationally expensive function from a callback or anywhere, to the same extent that you should be doing that in node in the first place. – djechlin Aug 20 '14 at 05:16
  • @djechlin: well, my answer (and the longer comment) is about how there’s no clear line between “synchronous” and “asynchronous” code. Even more than that, I don’t think there should be (and promises are a good way of accomplishing that). – Ry- Aug 20 '14 at 05:30
  • Maybe you're saying blocking calls e.g. for CPU intensive tasks are synchronous from the process's standpoint, but may "feel" asynchronous in wall time? but overall yes – djechlin Aug 20 '14 at 16:23
2

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.

Redu
  • 25,060
  • 6
  • 56
  • 76
  • I posted this question several years ago (in 2012), when this feature of JavaScript did not yet exist. – Anderson Green Nov 18 '21 at 23:15
  • @AndersonGreen Yes sure :) I just think your question is a good one and still valid so placed an answer for the sake completeness. – Redu Nov 19 '21 at 07:14