angular - Angular 递归 HTTP 请求,组合响应,最终返回单个 observable
问题描述
在浏览完所有页面之前,我想对分页 API 进行递归 HTTP 调用。每个页面都包含一个资产数组,我将它们连接到一个临时数组。阅读完所有页面后,我想将所有资产的单个数组作为可观察对象返回。
我一直在使用带有扩展运算符的管道。我注意到我可以在订阅完成时打印我的最终数组,但我不知道如何优雅地将这个数组作为可观察对象返回。有没有办法等待一个可观察的完成然后返回另一个?
getAllAssets(sort: string, filter: AssetFilter): Observable<Asset[]> {
let allAssets: Asset[] = [];
console.log('getAllAssets()', sort, filter);
this._getAllAssets(null, null).subscribe((moreAssets) => {
allAssets = allAssets.concat(moreAssets);
}, null, () => console.log(allAssets));
return of(allAssets);
}
_getAllAssets(sort: string, filter: AssetFilter) {
let currentPage = 0;
return this.getAssets(null, null, sort, filter).pipe(
expand(assetsPage => {
if (assetsPage && assetsPage.page.number + 1 < assetsPage.page.totalPages) {
return this.getAssets(currentPage += 1, null, sort, filter);
}
return empty();
}),
map((value) => value._embedded.assets)
);
}
getAssets(page: number, size: number, sort: string, filter: AssetFilter): Observable<Assets> {
let url = 'https://gateway.' + environment.region + '.mindsphere.io/api/assetmanagement/v3/assets?';
if (page) {
url += 'page=' + page;
}
if (size) {
url += 'size=' + size;
}
if (sort) {
url += 'sort=' + sort;
}
if (filter) {
url += 'filter=' + JSON.stringify(filter);
}
return this.http.get<Assets>(url, {
headers: new HttpHeaders().set('Content-Type', 'application/json').set('Authorization', 'Bearer ' + this.accessToken)
});
}
我将正确的数组打印到屏幕上,但我想将此数组作为可观察对象返回,而无需创建可观察对象,返回可观察对象,并在完成时向其发出。
编辑:我的解决方法是toArray()
如下所述使用。然后我只是做了一张地图把它Observable<item[][]>
变成Observable<item[]>
getAllAssets(sort: string, filter: AssetFilter): Observable<Asset[]> {
let currentPage = 0;
return this.getAssets(null, null, sort, filter).pipe(
expand(assetsPage => {
if (assetsPage && assetsPage.page.number + 1 < assetsPage.page.totalPages) {
return this.getAssets((currentPage += 1), null, sort, filter);
}
return empty();
}),
map(value => value._embedded.assets),
toArray()
).pipe(map(assets => [].concat.apply([], assets)));
}
getAssets(page: number, size: number, sort: string, filter: AssetFilter): Observable<Assets> {
let url = 'https://gateway.' + environment.region + '.mindsphere.io/api/assetmanagement/v3/assets?';
if (page) {
url += 'page=' + page;
}
if (size) {
url += 'size=' + size;
}
if (sort) {
url += 'sort=' + sort;
}
if (filter) {
url += 'filter=' + JSON.stringify(filter);
}
return this.http.get<Assets>(url, {
headers: new HttpHeaders().set('Content-Type', 'application/json').set('Authorization', 'Bearer ' + this.accessToken)
});
}
解决方案
这是一些需要筛选的代码,所以我将减少和概括,因为它是一种常见的模式,这将采用以下形式:
_getAllPages(page, constantArgs, lastSet) {
lastSet = lastSet || []; // deal with entry
return this.getPage(page, constantArgs).pipe( // fetch the page
switchMap(res =>
(res.nextPage) // if nextpage, recurse and concat to last set
? this._getAllPages(res.nextPage, lastSet.concat(res.items))
: of(lastSet.concat(res.items)))); // else break
}
出于风格目的,我通常会将其设为私有,并且我将有一个公众,例如:
getAllPages(constantArgs) {
return this._getAllPages(0, constantArgs);
}
使 API 更好/更容易理解。
推荐阅读
- java - 如何从 Canon RAW 文件 (.crw) 中提取创建日期等信息
- c++ - 为什么我的输出是负数?我乘以2个正数?
- java - 无法开始第二个活动(清单问题)
- yii2 - Yii2中UrlManager的问题
- javascript - 如何为具有条件的元素设置多个类
- django - 使用 Django Rest api 搜索模型返回空集
- python - 如何在 python PubSub 订阅者中捕获内部/库线程中发生的异常?
- python - 为什么这个解决方案有 O(nlogn) 复杂度?
- angular - 角路由和放置路由器插座
- python - 如何在调用 plt.show 之前创建多个图形而不显示它们?