skip to Main Content

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,
  '(() => {}).__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?

2

Answers


  1. Chosen as BEST ANSWER

    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.


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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search