使用switchMap切换Observable时仅返回单个条目问题排查
解决switchMap仅返回单个条目的问题
我来帮你分析下这个问题哈!你现在遇到的switchMap只返回单个条目,其实是switchMap的核心特性导致的——它每次有新的Observable进来时,会立刻取消之前还在进行的订阅。你用flatMap(locations=>locations)把locations数组拆成了一个个独立的location流,当第二个location流进来时,switchMap会直接取消第一个location对应的this.db.object(Devices/${location})请求,只保留最后一个,最终自然只能拿到单个结果。
下面给你几个针对性的解决方案,你可以根据自己的需求选择:
方案一:用mergeMap代替switchMap(并行处理)
mergeMap不会取消之前的订阅,而是会同时处理所有进来的Observable,适合需要并行获取所有设备数据的场景:
return this.db.list(`UserPlaces/${this.authData.auth.auth.currentUser.uid}`, { query: { orderByChild: 'deleted', equalTo: false } }) .map((locations: any) => { console.log(JSON.stringify(locations,null,2)); return locations.map(location => location.$key); }) .flatMap(locations => locations) .mergeMap(location => { // 替换switchMap为mergeMap console.log(location); return this.db.object(`Devices/${location}`); }) .do(console.log);
方案二:用concatMap代替switchMap(顺序处理)
如果你需要按顺序处理每个location的请求(前一个请求完成后再处理下一个),可以用concatMap:
return this.db.list(`UserPlaces/${this.authData.auth.auth.currentUser.uid}`, { query: { orderByChild: 'deleted', equalTo: false } }) .map((locations: any) => { console.log(JSON.stringify(locations,null,2)); return locations.map(location => location.$key); }) .flatMap(locations => locations) .concatMap(location => { // 替换switchMap为concatMap console.log(location); return this.db.object(`Devices/${location}`); }) .do(console.log);
方案三:用forkJoin一次性获取所有结果
如果你的需求是一次性拿到所有设备的数据(返回一个数组),可以用forkJoin来批量处理所有location的请求,它会在所有请求都完成后返回结果数组:
import { forkJoin } from 'rxjs'; // 需要先导入forkJoin return this.db.list(`UserPlaces/${this.authData.auth.auth.currentUser.uid}`, { query: { orderByChild: 'deleted', equalTo: false } }) .map((locations: any) => { console.log(JSON.stringify(locations,null,2)); return locations.map(location => location.$key); }) .switchMap(locationKeys => { // 把每个key转换成对应的设备Observable,然后用forkJoin合并 return forkJoin( locationKeys.map(key => this.db.object(`Devices/${key}`).valueChanges()) ); }) .do(console.log);
注意:forkJoin要求所有传入的Observable都完成才会返回结果,如果你的
db.object是持续推送数据的流,可能需要先加take(1)来获取单次结果,比如this.db.object(...).valueChanges().take(1)。
内容的提问来源于stack exchange,提问作者Khaled Ramadan
相关产品推荐
相关产品推荐

