user81993
user81993

Reputation: 6603

How to return an extended promise instance from an async function?

I'm just toying around with some ideas for my framework, lets say I extended the promise class like this

class cool_promise extends Promise {
    cool_function() {
        console.log("I am cool");
    }
}

and had an async function like

async cool_function() {
    return "functioning";
}

now by default cool_function just returns a regular Promise when executed synchronously but is it possible to make the async functions specific to my framework return my extended promise class instead?

Upvotes: 3

Views: 998

Answers (2)

Paul
Paul

Reputation: 141829

The async keyword will always cause a function to return a native Promise. To return a custom promise your function needs to be declared without async and return the Promise directly.

You could write your async functions like normal but wrap them with a function that returns a CoolPromise instead before exposing them as part of your framework's interface:

class CoolPromise extends Promise {
  coolFunction ( ) {
    return 'I am cool';
  }

  static decorate ( func ) {
    return function (...args) {
      return CoolPromise.resolve( func.call( this, ...args ) );  
    };
  }
}



// Some module with an async function in it

const module = function Module ( ) {
  async function foo( ) {
    return 'bar';
  }

  // Decorate functions before exposing them from your modules
  return {
    foo: CoolPromise.decorate( foo )
  };
}( );



// Verify that module.foo( ) returns a CoolPromise

(async ( ) => {
  console.log( await module.foo( ) );
  console.log( module.foo( ).coolFunction( ) );
})();

Upvotes: 2

Ry-
Ry-

Reputation: 224862

No, you would have to convert it manually with cool_promise.resolve(cool_function()). Without using a JavaScript preprocessor, async functions will always return a native Promise.

An alternative sometimes is to extend the native Promise prototype:

Object.defineProperty(Promise.prototype, 'cool_function', {
    configurable: true,
    writable: true,
    value() {
        console.log("I am cool");
    },
});

Modifying globals always risks conflicting with other libraries/user code or later changes to the language, though. Sometimes it’s better to just have a standalone function. Maybe it’ll be possible to use that kind of function in a pipeline similar to the method call syntax someday – for example, there’s a proposal that would let you do this or something like it:

const cool_extension = (promise) => {
    console.log("I am cool");
};

cool_function() |> cool_extension
// cool_function().cool_extension(), when extending prototype

And in the meantime, cool_extension(cool_function()) is not too bad and comfortably familiar.

Upvotes: 1

Related Questions