Angular 8中双API调用的async observable执行顺序问题求解
问题根因
- 你对
contact$的重复赋值导致删除操作的Observable永远不会被执行:Angular的async管道仅会订阅contact$最后一次被赋值的对象。你的代码先处理删除逻辑时给contact$赋值了删除接口的Observable,后续处理新增逻辑时直接覆盖了这个值为新增接口的Observable,最终只有新增请求会被触发,删除的Observable因为没有订阅者不会发起请求。 - 循环内重复调用接口的逻辑不合理:你不需要在遍历删除/新增列表的循环中反复调用接口,完全可以先把所有符合条件的删除、新增数据收集完成后,再统一处理接口调用。
修复方案
要保证删除操作执行完成后再调用保存接口,可以借助RxJS的concatMap操作符控制执行顺序,先统一收集所有待处理数据,再串行执行请求,最终统一赋值给contact$,修正后的代码如下:
组件TS代码
import { concatMap, of } from 'rxjs'; // ...其他代码省略 userChanges(contactList: any[]) { // 第一步:先统一收集所有符合条件的待删除、待新增数据 const contactsToDel: { pubType: string, masterOutlineId: number, idsv: number, idVariant: number, fn: string, ln: string, cid: string, role: string }[] = []; const contactsToAdd: { pubType: string, masterOutlineId: number, idsv: number, idVariant: number, fn: string, ln: string, cid: string, role: string }[] = []; let idsv: number | null = null; // 收集待删除数据 contactList.filter(c => c.mode == 'delete').forEach(contact => { if (contact.masterOutlineId === this.masterOutlineId && contact.idVariant === this.idVariant && contact.procuid === this.procuid) { if (!idsv) { idsv = this.idSVList.find(x => x.idv === contact.idVariant).idsv; this.idSV = idsv; } contactsToDel.push({ pubType: this.pubType, masterOutlineId: contact.masterOutlineId, idsv: idsv, idVariant: contact.idVariant, fn: contact.fn, ln: contact.ln, cid: contact.cid, role: contact.role }); } }); // 收集待新增数据 contactList.filter(c => c.mode == 'add').forEach(contact => { if (contact.masterOutlineId === this.masterOutlineId && contact.idVariant === this.idVariant && contact.procuid === this.procuid) { if (!idsv) { idsv = this.idSVList.find(x => x.idv === contact.idVariant).idsv; this.idSV = idsv; } contactsToAdd.push({ pubType: this.pubType, masterOutlineId: contact.masterOutlineId, idsv: idsv, idVariant: contact.idVariant, fn: contact.fn, ln: contact.ln, cid: contact.cid, role: contact.role }); } }); // 第二步:串行执行请求,先删后加,最终统一赋值给contact$ let request$ = of(null); // 有需要删除的数据就先执行删除请求 if (contactsToDel.length && idsv) { request$ = request$.pipe( concatMap(() => this.contactService.removeBulkContact(this.pubType, this.procuid, this.variantid, idsv, contactsToDel)) ); } // 删除执行完成后再执行新增请求 if (contactsToAdd.length && idsv) { request$ = request$.pipe( concatMap(() => this.contactService.saveContact(this.pubType, this.procuid, this.variantid, idsv, contactsToAdd)) ); } // 最终把整个串行请求流赋值给contact$ this.contact$ = request$; }
其他说明
模板和Service层的代码不需要修改,async管道会自动订阅整个串行请求流,保证删除完成后才会执行新增请求,最终渲染最新的返回数据。如果需要同时展示删除和新增的合并结果,可以在concatMap的回调中自行处理前后两次请求的返回值合并逻辑。
内容的提问来源于stack exchange,提问作者Margerine
相关产品推荐
相关产品推荐

