小编典典

异步/等待类构造函数

javascript

目前,我正在尝试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()?


阅读 630

收藏
2020-05-01

共1个答案

小编典典

永远 行不通。

async关键字允许await在标记为函数中使用async,但它也是功能转换成一个承诺发生器。因此,标有的函数async将返回承诺。另一方面,构造函数返回其正在构造的对象。因此,在这种情况下,您既要返回对象又要兑现承诺:一种不可能的情况。

您只能在可以使用诺言的地方使用async /
await,因为它们本质上是诺言的语法糖。您不能在构造函数中使用promise,因为构造函数必须返回要构造的对象,而不是promise。

有两种设计模式可以克服这一问题,它们都是在实现承诺之前发明的。

  1. 使用init()功能。这有点像jQuery的.ready()。您创建的对象只能在其自身initready函数内部使用:

用法:

    var myObj = new myClass();
myObj.init(function() {
    // inside here you can use myObj
});

实现方式:

    class myClass {
    constructor () {

    }

    init (callback) {
        // do something async and call the callback:
        callback.bind(this)();
    }
}
  1. 使用一个生成器。我没有看到它在javascript中使用很多,但是当对象需要异步构造时,这是Java中最常见的变通方法之一。当然,在构造需要大量复杂参数的对象时会使用构建器模式。这正是异步构建器的用例。不同之处在于异步生成器不会返回对象,而是返回该对象的承诺:

用法:

    myClass.build().then(function(myObj) {
    // myObj is returned by the promise, 
    // not by the constructor
    // or builder
});

// with async/await:

async function foo () {
    var myObj = await myClass.build();
}

实现方式:

    class myClass {
    constructor (async_param) {
        if (typeof async_param === 'undefined') {
            throw new Error('Cannot be called directly');
        }
    }

    static build () {
        return doSomeAsyncStuff()
           .then(function(async_result){
               return new myClass(async_result);
           });
    }
}

用async / await实现:

    class myClass {
    constructor (async_param) {
        if (typeof async_param === 'undefined') {
            throw new Error('Cannot be called directly');
        }
    }

    static async build () {
        var async_result = await doSomeAsyncStuff();
        return new myClass(async_result);
    }
}

注意:尽管在上面的示例中,我们对异步生成器使用了Promise,但严格来讲它们并不是必需的。您可以轻松地编写一个接受回调的构建器。


注意在静态函数内部调用函数。

这与异步构造函数无关,而与关键字的this实际含义无关(这对于使用自动解析方法名称的语言(即不需要this关键字的语言)来的人来说可能有点令人惊讶。

this关键字是指实例化的对象。不是班级。因此,您通常不能this在内部静态函数中使用,因为静态函数未绑定到任何对象,而是直接绑定到该类。

也就是说,在以下代码中:

class A {
    static foo () {}
}

您不能:

var a = new A();
a.foo() // NOPE!!

相反,您需要将其称为:

A.foo();

因此,以下代码将导致错误:

class A {
    static foo () {
        this.bar(); // you are calling this as static
                    // so bar is undefinned
    }
    bar () {}
}

要修复它,您可以bar使用常规函数或静态方法:

function bar1 () {}

class A {
    static foo () {
        bar1();   // this is OK
        A.bar2(); // this is OK
    }

    static bar2 () {}
}
2020-05-01