Tengo una función así:
let maybeRun = function (cb: Function, allow: boolean, ctx: object = window) { return function () { if (!allow) return; cb.call(ctx, ...arguments); // cb.apply(ctx, arguments); }; }; En caso de que cb sea síncrono no hay problema, pero ¿cómo debo manejar el caso de que cb devuelva una promesa (asíncrono)?
let cb = async ()=> {...}; let foo = maybeRun(cb, true); await foo() Quiero que la función devuelta foo tenga el mismo comportamiento que cb (sync o async).
No tienes que hacer nada especial en absoluto; una función async simplemente devuelve una promesa como cualquier otro valor de retorno.
Pero tenga en cuenta que le falta un return en su función de contenedor. Su función estaba descartando cualquier valor de retorno que obtuviera (incluida una promesa).
let maybeRun = function (cb: Function, allow: boolean, ctx: object = window) { return function () { if (!allow) return; // *** See note below return cb.call(ctx, ...arguments); // −−−−−^^^^^^ }; }; Una arruga es que su envoltorio ahora a veces devuelve una promesa y otras veces no. No hay nada (estándar) que pueda hacer para mirar cb (sin llamarlo) para ver si devuelve una promesa, por lo que puede ser una limitación con la que debe lidiar. ( Puede detectar si se trata de una función async , pero no puede saber si es una función no async que devuelve una promesa).
En un comentario, has dicho:
No escribí una devolución porque las funciones envueltas para las que necesito esta función no tienen devolución.
Eso cambia las cosas para su caso de uso específico: simplemente usaría await al llamar a la función:
let maybeRun = function (cb: Function, allow: boolean, ctx: object = window) { return async function () { // −−−−−−−−^^^^^ if (!allow) return; await cb.call(ctx, ...arguments); // −−−−−^^^^^ }; }; Ahora su función (que es async ) siempre devuelve una promesa, y en los casos en los que cb devuelve una promesa (ya sea explícitamente o porque es una función async ), su función esperará a que la promesa se liquide antes de regresar, pero no devolverá la valor de cumplimiento.
Tenga en cuenta que incluso con ese cambio, se llama a cb de forma síncrona cuando llama a la función contenedora que obtuvo de maybeRun . Una función async se ejecuta de forma síncrona hasta la primera vez que tiene que esperar algo. Si cb es síncrono, se ejecutará durante la ejecución síncrona inicial del contenedor.