Estoy tratando de escribir una "mezcla" para las clases de JavaScript (controladores, en mi aplicación) para "esperar" automáticamente a que se resuelva una función dada, antes de invocar los métodos reales. Los métodos de clase real deben recibir el valor resuelto como último argumento.
Aquí está el código de useAwait
, donde busco la propiedad de clase estática que awaits
y envuelvo el originalFunc
en uno nuevo async
. Estoy llamando a la nueva función pasando los argumentos originales más el resultado de la llamada asyncFn
:
const useAwait = (controller, asyncFn) => { controller.constructor.awaits.forEach(func => { const originalFunc = controller[func]; controller[func] = async (...args) => { return originalFunc.apply( controller, [...args, await asyncFn.call(controller)] ); }; }); }
Entonces, cuando se useAwait(ctrl, this.load)
en una instancia de esta clase:
class Controller { static awaits = ['foo', 'bar']; promise; constructor() { useAwait(this, this.load); } async foo(e, resolved) { return resolved; } bar(resolved) { return resolved; } async load() { if (!this.promise) { this.promise = new Promise(resolve => setTimeout(() => { resolve('Hello World!'); }, 3000)); } return this.promise; } }
El problema : todo parece estar bien para foo
(ya async
), pero no lo es para bar
: el resultado es una Promise
porque ahora la bar
está envuelta en async
(no antes). Sé que el resultado de una función asíncrona está envuelto en una Promise
. Ejemplo de Codepen donde la llamada de bar
genera "[objeto Promesa]".
Entonces, la pregunta es: en teoría, debería verificar si la función original es async
y, si no lo fue, ¿ await
su valor de retorno?
... en teoría, debería verificar si la función original es
async
y, si no lo es,await
su valor de retorno".
No importaría, su contenedor es async
; una función async
siempre devuelve una promesa, ya sea que use await
o no. Además, su contenedor no puede ser síncrono, porque necesita llamar awaitFn
( load
, en el ejemplo) y esperar su resultado.
Si va a envolver originalFunction
( bar
) de modo que espere a que se awaitFn
( load
), la versión envuelta debe ser asíncrona (ya sea async
o devolver una promesa explícitamente [o aceptar una devolución de llamada, pero mejor en mi humilde opinión] usar promesas]). No puede ser síncrono, porque awaitFn
( load
) no es síncrono.
Si la instancia de clase no está lista para usar cuando la construya, podría considerar usar un método estático para obtener una instancia en su lugar; la instancia estática devolvería una promesa que cumple con la instancia una vez que se completa la load
. Bosquejo aproximado:
class Controller { dataFromLoadingProcess; constructor(dataFromLoadingProcess) { this.dataFromLoadingProcess = dataFromLoadingProcess; } async foo(e, resolved) { // ...optionally use `this.dataFromLoadingProcess`... return resolved; } bar(resolved) { // ...optionally use `this.dataFromLoadingProcess`... return resolved; } static async createInstance() { await /*...the loading process...*/; return new Controller(/*...data from loading process here, perhaps...*/) } }