Nodejs async function prototype chain error

此生再无相见时 提交于 2021-01-28 11:36:35

问题


why this code compiles

var Person =  function() {
console.log("CALLED PERSON")};

Person.prototype.saySomething = function() {
console.log("saySomething PERSON")};

var ape = new Person();
ape.saySomething();

and this code throws error Cannot set property 'saySomething' of undefined

var Person =  async function() {
console.log("CALLED PERSON")};

Person.prototype.saySomething = function() {
console.log("saySomething PERSON")};

var ape = new Person();
ape.saySomething();

回答1:


When you use async function() {}, you are declaring an asynchronous function object. That's different than a regular function object. The asynchronous function object does not have a prototype.

So, when you try to do this:

var Person =  async function() {
  console.log("CALLED PERSON")
};

Person.prototype.saySomething = function() {
  console.log("saySomething PERSON")
};

Person.prototype is undefined because there is no prototype on an asynchronous function object. Thus attempting to assign something to Person.prototype.saySomething causes the error you see because Person.prototype is undefined.

There is some logic to this because an asynchronous function can't be used as a constructor because an asynchronous function always returns a promise so it can't ever return a new object as in let obj = new f(). So, there's no purpose in having a .prototype property because it can't be used that way.

If you really wanted to asynchronously create an object, you could always create an async factory function that returns a promise that resolves with an object.




回答2:


It is possible to add an async function in the end of the prototype chain.

Please notice that this works well in nodejs 8.11.1+.

// lets start with defining some cool async function who takes the time and 
// awaits a promise 

async function someCoolAsyncFunction() {
    // this let will be returned after timeout in a different value.
    let coolStuff = 'still boring';

    // do something cool which takes time 
    await new Promise((resolve, reject) => setTimeout(() => {
        coolStuff = 'an epiphany';
        resolve();
    }, 1000))
    return coolStuff;
}

// Now let's define the 'regular' prototype chain with it's boring functions.

function Person(p) { 
     this.constructorPropery = p;
     return this;
}

Person.prototype.notAsync = function() {
     // do something regular in the prototype chain
     console.log("Let's build some ",this.constructorPropery)
     this.kindOfPerson = 'Regular and boring'; 
     return this;   
}

// And now, lets add an async function to this chain

Person.prototype.someAsyncFunction = async function() {
    // you will still have access to 'this' in this function as long as the
    // previous function in the prototype chain returnes 'this'
    console.log('I used to be someone ',this.kindOfPerson);

    // Now, this is our time to shine, lets await something cool
    this.lifeChangingEvent = await someCoolAsyncFunction();
    console.log('Until I had ',this.lifeChangingEvent);
    a.kindOfPerson = 'enlightened';
    console.log('and now I am ', a.kindOfPerson);
    return this;
}

So this will work:

new Person('charachter').notAsync().someAsyncFunction();

But this WILL NOT work:

new Person('charachter').someAsyncFunction().notAsync();

And if you really need the data in 'this' outside the prototype chain you can also do:

let myself = new Person('charachter').notAsync();
console.log('myself.kindOfPerson is: ',myself.kindOfPerson);
myself.someAsyncFunction(); 
console.log('myself.kindOfPerson now is: ',myself.kindOfPerson);

Be sure to remember which prototype is an async function for which function or use your own naming convection for that.



来源:https://stackoverflow.com/questions/49205519/nodejs-async-function-prototype-chain-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!