Angular项目中Array.splice失效数组成员还原导致无限循环问题
Angular 分批处理数组第二次执行无限循环问题
问题表现
开发Angular 4项目实现分批删除逻辑:每次从存储id的数组中截取固定数量项传入Observable删除接口,等订阅回调返回成功后检查剩余数组,有剩余则继续下一批处理,无剩余则触发完成回调。
- 首次执行逻辑完全正常,原数组随处理流程逐步缩减至0项,流程正常结束
- 第二次触发逻辑时出现异常:接口发起前打印的数组长度符合预期,但接口响应返回后,原数组会突然恢复为初始的完整状态,最终触发无限循环
相关代码
组件内数组成员定义:
RemoveItemsArray : Array<number>;
事件入口处理函数:
HandleActions( action, payload ) { switch( action ) { case "finish": DoSomething(); break; case "remove": this.RemoveItemsArray = payload.items; this.ProcessRemoveItems(); break; } }
核心批处理函数:
ProcessRemoveItems() { let executeItems = this.RemoveItemsArray.splice(0, 10); this.service.RemoveItemsAPI( executeItems ) .subscribe ( response => { if( response.StatusCode == 200 ) { if( this.RemoveItemsArray.length > 0 ) { this.ProcessRemoveItems(); } else { this.HandleAction("finish",null); } } }); }
根本原因
问题出在数组赋值时直接持有外部传入的引用,没有做副本隔离:
splice方法会直接修改原数组,当执行this.RemoveItemsArray = payload.items时,组件内的RemoveItemsArray和外部传入的payload.items指向同一块内存地址,后续splice截取操作会直接修改外部的原始数组- 第二次触发逻辑时,若外部数据源是状态管理(如NgRx)中维护的不可变状态、父组件传入的固定引用输入值、事件中复用的固定数组实例,外部逻辑检测到原始数组被非法篡改后,会触发状态回滚/值重写,直接把数组重置为初始完整值
- 异步接口返回时读取到的是被重置后的完整数组,递归终止条件永远无法满足,最终进入无限循环
修复方案
在赋值待处理数组时创建浅拷贝,断开组件内部数组和外部数据源的引用关联,避免修改外部原始数据:
case "remove": // 通过扩展运算符创建数组浅拷贝,也可以用payload.items.slice()实现相同效果 this.RemoveItemsArray = [...payload.items]; this.ProcessRemoveItems(); break;
可选优化项
- 给接口订阅加上自动取消逻辑,比如用
take(1)操作符,或者绑定组件销毁事件用takeUntil终止订阅,避免内存泄漏 - 增加处理中锁标记,避免批处理未完成时重复触发事件,导致多个流程并行冲突
// 新增成员变量 isRemoving: boolean = false; ProcessRemoveItems() { if (this.isRemoving) return; this.isRemoving = true; let executeItems = this.RemoveItemsArray.splice(0, 10); this.service.RemoveItemsAPI( executeItems ) .pipe(take(1)) .subscribe ( response => { if( response.StatusCode == 200 ) { if( this.RemoveItemsArray.length > 0 ) { this.ProcessRemoveItems(); } else { this.isRemoving = false; this.HandleAction("finish",null); } } }); }
内容的提问来源于stack exchange,提问作者kepcrom
相关产品推荐
相关产品推荐

