目前,我正在尝试在类构造函数中使用async/await。这样我就可以为我正在进行的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()?
这是可以做到的。
一个简单的代码:
class test
{
constructor ()
{
return new Promise ( (resolve, reject) => { resolve(this); });
}
doHello() {console.log("hello");}
}
async function main()
{
let t = await new test(); //invoking synchronously
t.doHello(); //t is not a pormise
}
main();
或与上面相同,但添加了实际延迟,使用setTimeout
class test
{
constructor ()
{
return new Promise ( (resolve, reject) =>
{
setTimeout (resolve, 5, this);
});
}
doHello() {console.log("hello");}
}
async function main()
{
let t = new test(); //now t is a promise
t.then((a)=>{ a.doHello();}); //a is the real reference to test instance
console.log("testing"); //"testing" will be printed 5 seconds before "hello"
}
main();
这里是我在现实生活中的一段代码,使用异步图像加载:
class HeightMap extends GlVAObject
{
#vertices = [];
constructor (src, crossOrigin = "")
{
//super(theContextSetup);
let image = new Image();
image.src = src;
image.crossOrigin = crossOrigin;
return new Promise ( (resolve, reject) =>
{
image.addEventListener('load', () =>
{
//reading pixel values from image into this.#vertices
//and generate a heights map
//...
resolve(this);
} );
});
}
///...
}
async function main()
{
let vao = await new HeightMap ("./heightmaps/ArisonaCraterHeightMap.png");
///...
}
main();
@slebetmen的公认答案很好地解释了为什么这行不通。除了答案中给出的两种模式之外,另一种选择是仅通过自定义异步getter访问您的异步属性。然后构造函数()可以触发属性的异步创建,但是getter在使用或返回属性之前检查属性是否可用。
当你想在启动后初始化一个全局对象,并且你想在一个模块中做这件事时,这种方法特别有用。而不是在index.js中初始化并将实例传递到需要它的地方,只需在需要全局对象的地方调用模块。
使用
const instance = new MyClass();
const prop = await instance.getMyProperty();
实现
class MyClass {
constructor() {
this.myProperty = null;
this.myPropertyPromise = this.downloadAsyncStuff();
}
async downloadAsyncStuff() {
// await yourAsyncCall();
this.myProperty = 'async property'; // this would instead by your async call
return this.myProperty;
}
getMyProperty() {
if (this.myProperty) {
return this.myProperty;
} else {
return this.myPropertyPromise;
}
}
}
如果可以避免扩展,则可以一起避免类,并使用函数组合作为构造函数。你可以使用作用域中的变量代替类成员:
async function buildA(...) {
const data = await fetch(...);
return {
getData: function() {
return data;
}
}
}
简单的使用它
const a = await buildA(...);
如果你使用typescript或flow,你甚至可以强制构造函数的接口
Interface A {
getData: object;
}
async function buildA0(...): Promise<A> { ... }
async function buildA1(...): Promise<A> { ... }
...