如何使用RxJS Observable处理API返回空数组的代码失效问题
看起来你遇到的问题是当上游API返回空数组时,后续的RxJS流没法正常传递结果对吧?我来帮你分析下原因并给出解决方案。
先理清楚你的场景
首先你提到的API响应是这样的(返回空数组但HTTP状态码200):
HTTP/1.1 200 OK
Date: Tue, 16 Apr 2018 06:06:22 GMT
Content-Type: application/json; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
Request-Context: appId=cid-v1:...
[]
你的代码大致是这样的,但空数组场景下失效:
getData(): Observable<Thing[]> { return this.getData1() .pipe( flatMap(aData => { const ids = aData.map(({ id }) => id); const bData = this.getBData(ids); // 此处可能返回空结果 // 后续的订阅逻辑出问题 }) ); }
问题根源
最可能的原因是:当aData是空数组时,ids也会变成空数组。这时候如果getBData接收空数组后,要么返回了一个没有发射任何值的Observable(比如API调用被你提前拦截但没返回默认值),要么API返回空数组但你的流没有正确处理这种情况,导致flatMap没法向下传递任何数据,订阅者就收不到结果,看起来像是代码“卡住”了。
几个可行的解决方案
方案1:提前拦截空ids,直接返回空数组Observable
在调用getBData之前先判断ids是否为空,如果是空的,直接用of([])返回一个包含空数组的Observable,保证流能正常走下去:
import { of } from 'rxjs'; import { flatMap } from 'rxjs/operators'; getData(): Observable<Thing[]> { return this.getData1() .pipe( flatMap(aData => { const ids = aData.map(({ id }) => id); // 如果ids为空,直接返回空数组的Observable if (ids.length === 0) { return of([]); } return this.getBData(ids); }) ); }
方案2:给getBData加空参数处理
如果getBData是你自己封装的方法,不如直接在这个方法里处理空ids的情况,避免上游重复判断:
import { of } from 'rxjs'; import { HttpClient } from '@angular/common/http'; // 假设你用Angular的HttpClient constructor(private http: HttpClient) {} getBData(ids: number[]): Observable<Thing[]> { // 空数组直接返回默认值 if (ids.length === 0) { return of([]); } // 原来的API调用逻辑 return this.http.post<Thing[]>('/your-api-endpoint', { ids }); }
方案3:用defaultIfEmpty兜底空Observable
如果getBData在某些场景下确实会返回没有任何值的Observable(比如某些API在参数为空时不返回任何响应体),可以给它加上defaultIfEmpty([])操作符,确保至少会发射一个空数组:
import { of } from 'rxjs'; import { flatMap, defaultIfEmpty } from 'rxjs/operators'; getData(): Observable<Thing[]> { return this.getData1() .pipe( flatMap(aData => { const ids = aData.map(({ id }) => id); return this.getBData(ids).pipe( // 当Observable没有发射任何值时,自动发射空数组 defaultIfEmpty([]) ); }) ); }
你可以根据自己的实际场景选其中一个方案,应该就能解决空数组场景下的问题了。
内容的提问来源于stack exchange,提问作者Sergino

