如何修正firstLoad$与paged$两个Observable的加载顺序问题?
修正Observable执行顺序问题
你当前代码的问题在于使用了mergeMap,它会并行订阅firstLoad$和paged$两个Observable,哪个先完成就先触发后续的scan逻辑,完全不保证顺序。这就是paged$加载更快时执行顺序不符合预期的原因。
方案1:用concatMap替换mergeMap
concatMap会严格按照Observable的传入顺序串行处理——必须等前一个Observable完成并处理完毕,才会订阅下一个。修改后的代码如下:
of(firstLoad$, paged$) .pipe( concatMap((curr: Observable<ISubject[]>) => curr), scan((acc: ISubject[], curr: ISubject[]) => { if (acc.length > 0) { return [...curr]; } else { return [...acc, ...curr]; } }, []) ) .subscribe((result) => { if (result.length === 0) { setTimeout(() => { this.loading = false; }, 300); } else { this.subjects = this.subjects.concat(result); this.errorStatus = Array(this.subjects.length); this.subjectsSubject$.next(this.subjects); this.loading = false; } });
方案2:直接使用concat操作符(更简洁)
concat操作符本身就是用来按顺序拼接Observable的,不需要额外用of包裹,代码更直观:
concat(firstLoad$, paged$) .pipe( scan((acc: ISubject[], curr: ISubject[]) => { if (acc.length > 0) { return [...curr]; } else { return [...acc, ...curr]; } }, []) ) .subscribe((result) => { if (result.length === 0) { setTimeout(() => { this.loading = false; }, 300); } else { this.subjects = this.subjects.concat(result); this.errorStatus = Array(this.subjects.length); this.subjectsSubject$.next(this.subjects); this.loading = false; } });
原理说明
concat/concatMap的核心逻辑是串行订阅:先订阅firstLoad$,等它完成(发出所有数据并触发complete)后,才会订阅paged$。这样不管paged$的加载速度有多快,都会严格等待firstLoad$处理完成后再执行,完全保证你需要的顺序。
内容的提问来源于stack exchange,提问作者Joelad
相关产品推荐
相关产品推荐

