无法等待SweetAlert响应,如何等确认/取消后执行后续代码?
问题:SweetAlert确认框未等待用户操作就触发后续逻辑
我有一个点击触发的组件方法:
executeEditUser() { this.alertService.confirmationAlertUserEdit(); this.alertService.getBehaviorAlertEvent().subscribe({ next: (isConfirmed) => { if (isConfirmed) { this.userService.editUser(this.id, this.userModel).subscribe({ next: () => this.reloadResources(), error: (err) => this.alertService.errorAlert(err) }) } }, error: (err) => this.alertService.errorAlert(err) }) }
通过独立的alertService类调用SweetAlert确认对话框(含确认/取消按钮),根据用户操作通过BehaviorSubject触发事件,再由getBehaviorAlertEvent()的订阅处理逻辑。但问题是:对话框弹出后,还未点击确认/取消,后续的订阅代码就已执行。
以下是alertService中的弹窗代码:
confirmationAlertUserEdit() { Swal.fire({ title: 'Confirm user edit?', text: "Changes can be made again", icon: 'warning', showCancelButton: true, confirmButtonColor: '#3085d6', cancelButtonColor: '#d33', confirmButtonText: 'Save edit' }).then((result) => { if (result.isConfirmed) { Swal.fire( 'Edited!', 'User edited', 'success' ) this.behaviorAlertEvent.next(true); } else { this.behaviorAlertEvent.next(false); } }) }
解决方案
核心问题分析
问题根源在于BehaviorSubject的特性:它会保留最新的一次事件值,当新的订阅发生时,会立刻把这个旧值推送给订阅者。如果用户之前操作过弹窗,新的订阅会直接触发旧的结果;另外,全局BehaviorSubject容易导致多次订阅的内存泄漏,以及逻辑耦合问题。
方案1:改造弹窗方法返回Observable(推荐)
直接让confirmationAlertUserEdit返回一个Observable,替代全局BehaviorSubject,这样组件可以直接订阅弹窗的操作结果,逻辑更清晰且避免旧值干扰:
修改alertService代码:
import { Observable } from 'rxjs'; // ... confirmationAlertUserEdit(): Observable<boolean> { return new Observable(observer => { Swal.fire({ title: 'Confirm user edit?', text: "Changes can be made again", icon: 'warning', showCancelButton: true, confirmButtonColor: '#3085d6', cancelButtonColor: '#d33', confirmButtonText: 'Save edit' }).then((result) => { if (result.isConfirmed) { Swal.fire('Edited!', 'User edited', 'success'); observer.next(true); } else { observer.next(false); } observer.complete(); // 完成Observable,防止内存泄漏 }).catch(error => { observer.error(error); observer.complete(); }); }); }
修改组件的executeEditUser方法:
executeEditUser() { // 直接订阅弹窗返回的Observable,无需全局Subject this.alertService.confirmationAlertUserEdit().subscribe({ next: (isConfirmed) => { if (isConfirmed) { this.userService.editUser(this.id, this.userModel).subscribe({ next: () => this.reloadResources(), error: (err) => this.alertService.errorAlert(err) }); } }, error: (err) => this.alertService.errorAlert(err) }); }
方案2:改用Subject替代BehaviorSubject(兼容原有逻辑)
如果一定要保留全局事件的方式,将BehaviorSubject替换为普通Subject,因为Subject不会保留历史值,只有订阅后发送的事件才会被接收:
修改alertService中的Subject定义:
import { Subject } from 'rxjs'; // 替换原来的BehaviorSubject private behaviorAlertEvent = new Subject<boolean>(); getBehaviorAlertEvent(): Observable<boolean> { return this.behaviorAlertEvent.asObservable(); }
组件代码调整(可选):
为避免多次订阅内存泄漏,建议在组件销毁时取消订阅:
import { Subscription } from 'rxjs'; private alertSub!: Subscription; executeEditUser() { // 先取消之前的订阅 if (this.alertSub) { this.alertSub.unsubscribe(); } this.alertSub = this.alertService.getBehaviorAlertEvent().subscribe({ next: (isConfirmed) => { if (isConfirmed) { this.userService.editUser(this.id, this.userModel).subscribe({ next: () => this.reloadResources(), error: (err) => this.alertService.errorAlert(err) }); } }, error: (err) => this.alertService.errorAlert(err) }); // 最后调用弹窗 this.alertService.confirmationAlertUserEdit(); } // 组件销毁时清理订阅 ngOnDestroy() { if (this.alertSub) { this.alertSub.unsubscribe(); } }
内容的提问来源于stack exchange,提问作者Andrеw
相关产品推荐
相关产品推荐

