Por el momento, estoy intentando usar async/await dentro de una función de constructor de clase. Esto es para que pueda obtener una etiqueta e-mail personalizada para un proyecto de Electron en el que estoy trabajando.
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> ` } })Por el momento sin embargo, el proyecto no funciona, con el siguiente error:
Class constructor may not be an async method¿Hay alguna manera de eludir esto para que pueda usar async/await dentro de esto? En lugar de requerir devoluciones de llamada o .then()?
Definitivamente puede hacer esto, devolviendo una expresión de función asíncrona invocada inmediatamente desde el constructor. IIAFE es el nombre elegante de un patrón muy común que se requería para usar await fuera de una función asíncrona, antes de que la espera de nivel superior estuviera disponible:
(async () => { await someFunction(); })(); Usaremos este patrón para ejecutar inmediatamente la función asíncrona en el constructor y devolver su resultado como this :
// Sample async function to be used in the async constructor async function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } class AsyncConstructor { constructor(value) { return (async () => { // Call async functions here await sleep(500); this.value = value; // Constructors return `this` implicitly, but this is an IIFE, so // return `this` explicitly (else we'd return an empty object). return this; })(); } } (async () => { console.log('Constructing...'); const obj = await new AsyncConstructor(123); console.log('Done:', obj); })();Para instanciar la clase, use:
const instance = await new AsyncConstructor(...);Para TypeScript, debe afirmar que el tipo del constructor es el tipo de clase, en lugar de una promesa que devuelve el tipo de clase:
class AsyncConstructor { constructor(value) { return (async (): Promise<AsyncConstructor> => { // ... return this; })() as unknown as AsyncConstructor; // <-- type assertion } }super en el constructor de la clase derivada, tendrá que llamarlo sin await . Si necesita llamar al superconstructor con await , se encontrará con el error 2337 de TypeScript: las superllamadas Super calls are not permitted outside constructors or in nested functions inside constructors. Antes de usar esta solución, determine si necesitará extender la clase y documente que se debe llamar al constructor con await .
Debido a que las funciones asíncronas son promesas, puede crear una función estática en su clase que ejecute una función asíncrona que devuelva la instancia de la clase:
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() Llame con let yql = await Yql.init() desde una función asíncrona.