javascript - 避免多次按下回车按钮时的多个 http 调用

标签 javascript angular rxjs

我有一个按钮,可以在键盘输入时调用 API。如果他们立即多次进入,就会变成“n”。通话次数。

如何使用干净的通用解决方案避免这种情况,以便它可以在任何地方使用?

    <button click="initiateBulkPayment()(keyup.enter)="initiateBulkPayment">

    initiateBulkPayment = (orderId:any, payment_methods:any) => {
       let postParams = payment_methods;
       console.log('this is payment_method', payment_methods);


       return this.http.post(Constants.API_ENDPOINT + '/oms/api/orders/' + 
           orderId + '/payments/bulk_create/', postParams, this.auth.returnHeaderHandler())
          .pipe(map((data: any) => {
           return data;
       }),
       catchError((err)=>{
         return throwError(err);
       }));
   }

最佳答案

有两种解决方法:

  1. 在执行调用时禁用按钮
  2. 跳过多余的调用

在执行调用时禁用按钮:

<button [disabled]="paymentRequest.inProgress$ | async" (click)="onPayButtonClick()">
export class ProgressRequest {
    private _inProgress$ = new UniqueBehaviorSubject(false);

    execute<TResult>(call: () => Observable<TResult>): Observable<TResult> {
        if (!this._inProgress$.value) {
            this._inProgress$.next(true);
            return call().pipe(
                finalize(() => {
                    this._inProgress$.next(false);
                })
            );
        } else {
            throw new Error("the request is currently being executed");
        }
    }

    get inProgress$(): Observable<boolean> {
        return this._inProgress$;
    }
}

@Component({ ... })
export class MyComponent {
    readonly paymentRequest = new ProgressRequest();

    onPayButtonClick() {
        this.paymentRequest.execute(() => {
            return this.http.post(
                Constants.API_ENDPOINT + '/oms/api/orders/' + orderId + '/payments/bulk_create/',
                postParams,
                this.auth.returnHeaderHandler()
            ).pipe(map((data: any) => {
                return data;
            });
        }).subscribe(data => {
            console.log("done!", data);
        });
    }
}

跳过多余的调用:

您可以使用 exhaustMap在执行前一个请求时跳过请求。请注意,其他答案中建议的 switchMapshareReplay 不会阻止过多的 http 调用。

<button #paymentButton>
@Component({ ... })
export class MyComponent implements OnInit {
    @ViewChild('paymentButton', { static: true })
    readonly paymentButton!: ElementRef<HTMLElement>;

    ngOnInit() {
        merge(
            fromEvent(this.paymentButton.nativeElement, 'click'),
            fromEvent<KeyboardEvent>(this.paymentButton.nativeElement, 'keyup').pipe(
                filter(event => event.key === "Enter")
            )
        ).pipe(
            exhaustMap(() => {
                return this.http.post(
                    Constants.API_ENDPOINT + '/oms/api/orders/' + orderId + '/payments/bulk_create/',
                    postParams,
                    this.auth.returnHeaderHandler()
                ).pipe(map((data: any) => {
                    return data;
                });
            })
        ).subscribe(result => {
            console.log(result);
        });
    }
}

请注意,当您按下 enter 键时,也会触发 click 事件,因此无需监听“keyup”。

// You can replace
merge(
    fromEvent(this.paymentButton.nativeElement, 'click'),
    fromEvent<KeyboardEvent>(this.paymentButton.nativeElement, 'keyup').pipe(
        filter(event => event.key === "Enter")
    )
)

// just by
fromEvent(this.paymentButton.nativeElement, 'click')

关于javascript - 避免多次按下回车按钮时的多个 http 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57654064/

相关文章:

javascript - 为什么多个日期选择器不起作用?

php - AJAX+PHP投票系统

javascript - Angular "scheduler.schedule is not a function"使用 observable

javascript - 单击链接与复制粘贴链接时浏览器行为的差异?

javascript - 如何在对话框窗口上放置确认对话框?

angular - 从 Angular4 中的子组件填充父组件中的多个占位符

javascript - 在谷歌地图上添加多个标记

javascript - 使用 Angular 从 API 访问数据(格式错误?)

javascript - 如何通过重新连接实现 shareReplay?

javascript - 组合最新运算符替代方案