异步/等待类构造函数

目前,我正在尝试async/await在类构造函数中使用。这样一来,我就可e-mail以为正在从事的Electron项目获取自定义标签。

customElements.define('e-mail', class extends HTMLElement {
  async constructor() {
    super()

    let uid = this.getAttribute('data-uid')
    let message = await grabUID(uid)

    const shadowRoot = this.attachShadow({mode: 'open'})
    shadowRoot.innerHTML = `
      <div id="email">A random email message has appeared. ${message}</div>
    `
  }
})

但是,目前该项目无法正常工作,并出现以下错误:

Class constructor may not be an async method

有没有办法避免这种情况,以便我可以在其中使用异步/等待?而不需要回调或.then()?

米亚2020/04/03 12:19:52

与其他人所说的不同,您可以使其正常工作。

JavaScript class可以从其字面上返回任何内容constructor,甚至可以返回另一个类的实例。因此,您可能Promise从类的构造函数返回一个解析为其实际实例的a。

下面是一个示例:

export class Foo {

    constructor() {

        return (async () => {

            // await anything you want

            return this; // Return the newly-created instance
        }).call(this);
    }
}

然后,您将以Foo这种方式创建实例

const foo = await new Foo();
Tom凯2020/04/03 12:19:52

您可以立即调用返回消息的匿名异步函数并将其设置为message变量。如果您不熟悉这种模式,则可能要看一下立即调用的函数表达式(IEFES)。这将像魅力一样工作。

var message = (async function() { return await grabUID(uid) })()
泡芙2020/04/03 12:19:52

使用call()生成器模式的变化:

function asyncMethod(arg) {
    function innerPromise() { return new Promise((...)=> {...}) }
    innerPromise().then(result => {
        this.setStuff(result);
    }
}

const getInstance = async (arg) => {
    let instance = new Instance();
    await asyncMethod.call(instance, arg);
    return instance;
}
伽罗理查德2020/04/03 12:19:52

如果可以避免 extend,则可以一起避免类,并可以将函数组合用作构造函数您可以在范围中使用变量而不是类成员:

async function buildA(...) {
  const data = await fetch(...);
  return {
    getData: function() {
      return data;
    }
  }
}

并简单地用作

const a = await buildA(...);

如果您使用的是 TypeScript或流,您甚至可以强制执行构造函数的接口

Interface A {
  getData: object;
}

async function buildA0(...): Promise<A> { ... }
async function buildA1(...): Promise<A> { ... }
...
飞云JinJin2020/04/03 12:19:51

绝对可以做到这一点。基本上:

class AsyncConstructor {
    constructor() {
        return (async () => {

            // All async code here
            this.value = await asyncFunction();

            return this; // when done
        })();
    }
}

创建类使用:

let instance = await new AsyncConstructor();

该解决方案虽然有一些不足之处:

super注意:如果需要使用super,则不能在异步回调中调用它。

TypeScript注意:这会导致TypeScript问题,因为构造函数返回type Promise<MyClass>而不是MyClass据我所知,没有确定的方法可以解决此问题。@blitter建议的一种可能方式是放在/** @type {any} */构造函数主体的开头,但是我不知道这是否在所有情况下都有效。

古一小哥2020/04/03 12:19:51

在构造中使用异步方法???

constructor(props) {
    super(props);
    (async () => await this.qwe(() => console.log(props), () => console.log(props)))();
}

async qwe(q, w) {
    return new Promise((rs, rj) => {
        rs(q());
        rj(w());
    });
}
樱小胖Mandy2020/04/03 12:19:51

因为异步函数是承诺,所以您可以在类上创建一个静态函数,该函数执行一个异步函数,该函数返回该类的实例:

class Yql {
  constructor () {
    // Set up your class
  }

  static init () {
    return (async function () {
      let yql = new Yql()
      // Do async stuff
      await yql.build()
      // Return instance
      return yql
    }())
  }  

  async build () {
    // Do stuff with await if needed
  }
}

async function yql () {
  // Do this instead of "new Yql()"
  let yql = await Yql.init()
  // Do stuff with yql instance
}

yql()

与呼叫let yql = await Yql.init()从一个异步函数。