Tengo un clic que llama al método:
public clickEvent() { this.createIframe().then((iframe) => { // Return iframe or create if is not before needed inside // Async hard logic here }) } El problema es que cuando el usuario hace clic muchas veces en clickEvent() , se activa la promesa y luego se activa una lógica dura en el interior.
¿Cómo evitar hacer clic hasta que la lógica interna no esté terminada? ¿O deshabilitar para llamar a la lógica interna si está hecho?
Haga createIframe caché su Promesa (como una propiedad de instancia) y devuélvalo primero si existe, en lugar de iniciar otro. Por ejemplo:
// example function that creates the Promise const createPromise = () => { console.log('creating Promise'); return new Promise(resolve => setTimeout(resolve, 3000)); } class SomeClass { createIframe() { if (this.iframePromise) return this.iframePromise; this.iframePromise = createPromise(); return this.iframePromise; } clickEvent() { this.createIframe().then((iframe) => { console.log('clickEvent has received the Promise and is now running more code'); }) } } const s = new SomeClass(); button.onclick = () => s.clickEvent(); <button id="button">click to call clickEvent</button> Si también desea evitar que // Async hard logic here ejecute varias veces después de varios clics, asigne algo a la instancia dentro clickEvent en su lugar.
// example function that creates the Promise const createPromise = () => { console.log('creating Promise'); return new Promise(resolve => setTimeout(resolve, 3000)); } class SomeClass { createIframe() { return createPromise(); } clickEvent() { if (this.hasClicked) return; this.hasClicked = true; this.createIframe().then((iframe) => { console.log('clickEvent has received the Promise and is now running more code'); }) } } const s = new SomeClass(); button.onclick = () => s.clickEvent(); <button id="button">click to call clickEvent</button>Si está utilizando Angular, creo que puede convertir el evento de clic en un observable y luego usar la variedad de operadores como exhaustMap para lograrlo.
import { exhaustMap, fromEvent } from 'rxjs'; .... @ViewChild('btnId') btnElementRef!: ElementRef<HTMLButtonElement>; ngAfterViewInit(): void { fromEvent(this.btnElementRef.nativeElement, 'click') .pipe( exhaustMap(() => this.createIframe()) ) .subscribe((iframe) => { // hard coded async logic here }); } );Esto ignorará el clic subsecuente hasta que la Promesa se resuelva primero.
Además, si desea deshabilitar el botón y mostrar algún tipo de indicador de carga, también puede agregar una variable para rastrear eso dentro de la transmisión usando tap
fromEvent(this.btnElementRef.nativeElement, 'click') .pipe( tap(() => isProcessing = true), exhaustMap(() => this.createIframe()) ) .subscribe((iframe) => { isProcessing = false; // hard coded async logic here });