我必须执行多个GET请求才能从外部页面加载数据。
a请求的响应可能返回一个标志,指示有更多数据要加载: “ nextPage”:“ / v1 / catalog / products?page = 2&pageSize = 10”,
下面是我的函数代码。
我试图实现一个do while循环,但无法使其正常工作。我想还有一种更聪明的方式可以做到这一点-也许是Switchmap?
旧版本
loadCatalog() {
return new Promise((resolve, reject) => {
this.http.get<Catalog[]>(ZUORA_URL + '/v1/catalog/products?page=1&pageSize=10', { headers })
.pipe(map(data => data))
.subscribe(data => {
this.catalog = data;
resolve(true);
});
});
}
我想加载完整的数据并将其存储在一个地方。如何循环播放,直到没有其他下一页? -现在可以一页一页地加载,但是我仍在努力存储响应...
更新版本
getProducts(url, dataSoFar = []): Observable<any[]> {
if (!url) {
return of (dataSoFar);
} else {
url = ZUORA_URL + url;
}
return this.http.get<any>(url, { headers }).pipe(
switchMap(p => this.getProducts( p.nextPage, [...dataSoFar, ...p.data]))
);
}
getData() {
return this.getProducts('/v1/catalog/products');
}
答案 0 :(得分:0)
我真的不确定是否建议用Promise包装可观察对象并作为副作用更新数据。
loadCatalog(URL) {
return new Promise((resolve, reject) => {
this.http.get<Catalog[]>(ZUORA_URL + URL , { headers })
.pipe(map(data => data))
.subscribe(data => {
resolve(data);
});
});
}
现在您可以链接请求以获取数据,如下所示
async loadAllCatalogs(URL) {
return new Promise((resolve, reject) => {
try {
let catalogs = [];
let data = await this.loadCatalog('/v1/catalog/products?page=1&pageSize=10');
catalogs.push(data); // store catalog as an array since there may be more results based on nextPage key
while(data.nextPage) {
data = await this.loadCatalog(data.nextPage);
catalogs.push(data);
}
resolve(catalogs);
}
} catch (e) {
reject(e);
}
});
}
答案 1 :(得分:0)
您可以使用expand
递归调用api,并可以使用reduce
减少对单个数组的所有响应。
在您的Service
(MyService)中:
import { EMPTY } from 'rxjs';
import { expand, reduce, map } from 'rxjs/operators';
baseUrl = ZUORA_URL;
// Let's say you get an object like this from your API
interface ApiResponse {
nextPage: string,
data: any[]
}
public fetchData(apiEndpoint: string): Observable<any[]> {
return this.http.get<ApiResponse>(baseUrl + apiEndpoint, { headers })
.pipe(
// recursively call the GET requests until there is no further 'nextPage' url
expand(apiResponse => {
if (!apiResponse.nextPage) {
return EMPTY;
}
return this.http.get<ApiResponse>(apiResponse.nextPage, { headers });
}),
// map the api response to the data we actually want to return
map(apiResponse => apiResponse.data),
// reduce the data of all GET requests to a single array
reduce((accData, data) => accData.concat(data))
)
}
在您的组件中:
private products: Product[];
loadProducts() {
this.myService.fetchData('/v1/catalog/products').subscribe(products =>
this.products = products as Product[]
)
}
答案 2 :(得分:0)
通常,在对页面进行分页时,您只希望在用户主动请求时才获取它们。但是,我将直接回答您的问题,而把演讲留在外面。
我不确定在期望将数组作为响应中的顶级数组时如何包含nextPage
,因此,我将假定响应实际上是以下形式:< / p>
interface CatalogResponse {
nextPage: string | undefined;
products: Catalog[];
}
为此,您可以使用Observable
。
public loadProducts(url: string): Observable<Catalog[]> {
let nextPage: Subject<string> = new Subject<string>();
let products: Subject<Catalog[]> = new Subject<Catalog[]>();
nextPage.subscribe((url: string) => {
this.fetchProducts(url, products, nextPage);
}).add(() => products.complete());
return products;
}
private fetchProducts(url: string, products: Subject<Catalog[]>, nextPage: Subject<string>): void {
this.http.get<CatalogResponse>(url, { headers })
.subscribe(response => {
products.next(response.products);
if (response.nextPage) {
nextPage.next(response.nextPage);
} else {
nextPage.complete();
}
});
}
如果要无限期地进行操作,您需要确保执行“取消”或“停止”操作。