RxJS如何按数组原顺序串行执行from创建的Observable
问题根因
现有代码无法实现顺序输出的核心原因:from(this.arr)搭配普通map操作符,只会同步把数组元素映射为Observable实例,不会等待上一个Observable执行完毕就会生成下一个实例,所有Observable本质是并行触发,最终输出会按照setTimeout的延迟时长排序,和原数组顺序不一致。
修复方案
使用concatMap操作符替换原有map即可。concatMap会严格按照上游值的推送顺序,依次订阅每一个内部Observable,必须等前一个Observable执行完成后,才会启动下一个Observable的订阅,天然匹配顺序执行的要求。
修复后的完整代码:
import { from, Observable } from 'rxjs'; import { concatMap } from 'rxjs/operators'; export class AppComponent{ arr: number[] = [5, 4, 1, 2, 3]; fetchWithObs() { from(this.arr) .pipe( concatMap((value) => this.getData(value)) ) .subscribe((data) => { console.log(data); /** * 输出顺序完全符合预期: * 5 completed * 4 completed * 1 completed * 2 completed * 3 completed */ }); } getData(p: number) { return new Observable<string>((s) => { setTimeout(() => { s.next(`${p} completed`); s.complete(); }, p * 1000); }); } }
注意:使用前需要确认已从rxjs相关依赖包中引入
from、Observable和concatMap。
执行逻辑说明
- 串行执行总耗时为所有单个Observable耗时之和:5+4+1+2+3=15秒,和并行执行(总耗时等于最长单个任务耗时5秒)有明显差异
- 执行流程严格跟随数组顺序:先订阅5对应的Observable,等待5秒输出结果并完成后,才会订阅4对应的Observable,等待4秒输出后再处理下一个值,全程不会打乱顺序
- 禁止用
mergeMap/switchMap替代concatMap:mergeMap会并行订阅所有内部Observable,switchMap会中断未完成的前序Observable,都无法满足顺序执行要求
内容的提问来源于stack exchange,提问作者Gyan
相关产品推荐
相关产品推荐

