-1

This is a simple task in a web browser but in NodeJS it makes no distinction:

console.log({
  // 'Function' in browser, but empty string ('') in NodeJS
  '(() => {}).constructor.name': (() => {}).constructor.name,
  '(async () => {}).__proto__.constructor.name': (async () => {}).__proto__.constructor.name,

  // 'AsyncFunction' in browser, but empty string ('') in NodeJS 
  '(async () => {}).constructor.name': (async () => {}).constructor.name,
  '(async () => {}).__proto__.constructor.name': (async () => {}).__proto__.constructor.name,
  
  // Evaluates to false in browser, but true in NodeJS
  '(async () => {}).constructor === (() => {}).constructor': (async () => {}).constructor === (() => {}).constructor,
  '(async () => {}).__proto__ === (() => {}).__proto__': (async () => {}).__proto__ === (() => {}).__proto__,
  '(async () => {}).__proto__.constructor === (() => {}).__proto__.constructor': (async () => {}).__proto__.constructor === (() => {}).__proto__.constructor,
});

The reason I want to distinguish this is so I can indiscriminately add wrapper code while maintaining the function's "signature". If I were to convert everything to just accept a thenable object via Promise.resolve then I would have to make most all function calls into async methods (or expecting an async thenable). This is a problem for nodejs (or React Native) as it exercises the Promises/A+ specification, so indiscriminately expecting everything to be async does change the functionality of the code.

Does anyone know how to accomplish this or some kind of workaround in the meantime?

7
  • 1
    What version of nodejs are you using? Are you using a transpiler? Commented Nov 16, 2023 at 9:37
  • Don't use .__proto__, it's deprecated. Call Object.getPrototypeOf() instead. Commented Nov 16, 2023 at 9:38
  • 1
  • 2
    Using Node.js v20.0.0 (and v18, v17, v16, v15, v11, and v10), I don't get the results you report above. I get 'Function', 'AsyncFunction', 'AsyncFunction', false, false, false. And that makes sense, since Node.js uses V8, the same JavaScript engine used in the Chromium browsers. I wouldn't expect V8 to work differently in this regard in a browser vs. Node.js. It sounds like you're transpiling or something. Commented Nov 16, 2023 at 9:42
  • 1
    Does this answer your question? How to know if a function is async? Commented Nov 16, 2023 at 9:43

2 Answers 2

0

I want to distinguish this is so I can indiscriminately add wrapper code while maintaining the function's "signature"

Then you should not care whether the function was defined using async/await syntax or not.

You should care whether it returns a promise or not, when you call it. And that's distinguishable easily.

Sign up to request clarification or add additional context in comments.

2 Comments

Due to transpilers (or compilers, I don't know what to call it) using Promises/A+ specification, it will break the current thread, which is undesirable when I want certain synchronous code to continue executing.
@Steven - It doesn't matter whether the function uses async/await or returns a promise (or some other thanable) some other way. What matters is just whether it returns a promise (well, a thenable). The link Bergi gives above does exactly what you've done in your answer -- looks for a then method.
0

My temporary workaround is to test if the result is a thenable and return an asynchronous anonymous function awaiting on the result.

const debug = (message, fn) => {
  const reportError = (e, isSync) => {
    console.error(`${message}: ${e.message || e} (${isSync})`);
    throw e;
  };
  return (...args) => {
    try {
      // First, attempt to execute the provided function as if it is synchronous
      const result = fn?.(...args);

      // If its result is a thenable, then catch any errors while awaiting its response
      if (typeof result?.then === 'function') {
        return (async () => {
          try {
            return await result;
          }
          catch (e) { reportError(e, false); }
        })();
      }

      return result;
    }
    catch (e) { reportError(e, true); }
  };
};

It feels like it should be reducible further, but the result needs to be awaited on (I believe?) to be able to catch the rejected promise.

EDIT: Because I'm using TypeScript in my React Native project, it's transpiling the code such that the async functions appear just as synchronous ones do.

1 Comment

This is basically what Bergi was saying to do in his answer. He even points to a previous answer about how to detect a thenable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.