Búsqueda de sitios web

angular - Esperar a que una función asíncrona devuelva un valor en Typescript


Tengo una función (Function1) que llama a otra función (Function2) que devuelve una cadena.

Quiero que Function1 llame a Function2, pero espere y obtenga el valor de retorno de Function2. ¿Cómo se hace eso? Aquí está mi código (el cual no funciona como se desea):

Aquí está mi Function1:

async Function1() {
    const message = await this.dialogButtonPress();
    alert(message);
}

Aquí está mi Function2:

async dialogButtonPress() : Promise<string> {
    const doneButtonPromise = new Promise((resolve) => {
        const doneButton = document.getElementById("done-button");
        const resolver = () => {
            resolve();
            doneButton.removeEventListener("click", resolver);
        }
        doneButton.addEventListener("click", resolver);
    });

    const cancelButtonPromise = new Promise((resolve) => {
        const cancelButton = document.getElementById("cancel-button");
        const resolver = () => {
            resolve();
            cancelButton.removeEventListener("click", resolver);
        }
        cancelButton.addEventListener("click", resolver);
    })

    doneButtonPromise.then(() => {
        console.log("DONE BUTTON PRESSED!");
        return "Confirm";

    });

    cancelButtonPromise.then(() => {
        console.log("CANCEL BUTTON PRESSED!");
        return "Cancel";
    });      
}

Respuesta #1

Si usas Promise.race como sugiere la otra respuesta, no estarás limpiando el controlador de eventos para el botón que no fue presionado. Solo estarás limpiando el controlador para el botón que fue presionado. Si fuera yo, simplemente combinaría los controladores de eventos para asegurarme de que todo se limpie cuando se presione cualquier botón:

async dialogButtonPress(): Promise<string> {
    return new Promise<string>((resolve) => {
        const doneButton = document.getElementById("done-button")!;
        const cancelButton = document.getElementById("cancel-button")!;
        const resolver = (ev: Event) => {
            doneButton.removeEventListener("click", resolver);
            cancelButton.removeEventListener("click", resolver);
            // This is where we determine which button was clicked.
            resolve(ev.target === doneButton ? "Confirm" : "Cancel");
        }
        doneButton.addEventListener("click", resolver);
        cancelButton.addEventListener("click", resolver);
    });
}

Y podría escalar a cualquier número de botones:

async dialogButtonPress(): Promise<string> {
    return new Promise<string>((resolve) => {
        // You just need to expand this map in order to support additional buttons.
        const idToResponse: Record<string, string> = {
            "done-button": "Confirm",
            "cancel-button": "Cancel",
        };
        const buttons = Object.keys(idToResponse).map((id) => document.getElementById(id)!);
        const resolver = (ev: MouseEvent) => {
            for (const button of buttons) {
                button.removeEventListener("click", resolver);                    
            }
            // We index into idToResponse to convert the button's id to a specific response.
            resolve(idToResponse[(ev.target as Element).id]);
        }

        for (const button of buttons) {
            button.addEventListener("click", resolver);
        }
    });
}

Respuesta #2

Cambiar

doneButtonPromise.then(() => {
    console.log("DONE BUTTON PRESSED!");
    return "Confirm";

});

cancelButtonPromise.then(() => {
    console.log("CANCEL BUTTON PRESSED!");
    return "Cancel";
});

A

return Promise.race([
    doneButtonPromise.then(() => {
        console.log("DONE BUTTON PRESSED!");
        return "Confirm";
    }),
    cancelButtonPromise.then(() => {
        console.log("CANCEL BUTTON PRESSED!");
        return "Cancel";
    })
]);

Artículos relacionados