gpt4 book ai didi

angular - 使用 RXJS 继续以 Angular 触发 http 调用,直到满足条件

转载 作者:行者123 更新时间:2023-12-04 14:53:13 26 4
gpt4 key购买 nike

我正在调用 spotify api,它返回一个像这样的对象:

{
next: 'https://api.spotify.com/v1/me/tracks?offset=100&limit=50'
items: [...]
}

其中 items 是刚刚进行的网络调用的结果,next 是用于获取下“页面”结果的 url。我想做的是在没有偏移的情况下进行初始调用,然后继续进行网络调用直到 next 为空,这意味着用户没有更多的项目可以获取。如果没有更多项目,他们会为下一个返回 null。

这似乎是可能的,但似乎无法弄清楚如何正确地做到这一点。我正在寻找的是这样的东西:

  readonly baseSpotifyUrl: string = 'https://api.spotify.com/v1';

constructor(private http: HttpClient) {}


public getTracks(url?: string): Observable<any> {
return this.http.get(url && url?.length > 0 ? url : `${this.baseSpotifyUrl}/me/tracks?limit=50`);
}

public getAllTracks(): Observable<any> {
const tracks$: Subject<any> = new Subject();
let next: string = '';
this.getTracks(next)
.subscribe({
next: (res: any): void => {
tracks$.next(res.items);
next = res.next;
// if res.next !== null, do this again now that we have set next to res.next
},
error: (err: any): void => {
console.error(err);
}
});
return tracks$;
}

这里的想法是,我的组件将调用 getAllTracks() 并接收一个主题,然后新项目将不断推送到该主题,直到检索到所有项目。我似乎无法弄清楚如何在前一个返回时发出新的网络请求只有在有更多项目要获取时才返回(res.next!== null)

编辑-------------------------------------------- --------------

这完成了工作,但我觉得它很垃圾:

  public getAllTracksSegment(itemsSubject: Subject<any>, nextSubject: Subject<string>, url?: string): void {
this.http.get(url && url?.length > 0 ? url : `${this.baseSpotifyUrl}/me/tracks?limit=50`).subscribe({
next: (res: any): void => {
itemsSubject.next(res.items);
nextSubject.next(res.next);
}
});
}

public getAllTracks(): Observable<any> {
const tracks$: Subject<any> = new Subject();
const next$: Subject<string> = new Subject();
next$.subscribe({
next: (next: any): void => {
if (next !== null) {
this.getAllTracksSegment(tracks$, next$, next);
}
}
});
next$.next('');
return tracks$;
}

最佳答案

如果我对问题的理解正确,我会使用 expand 运算符来构建解决方案。

这是我要使用的代码。评论是内联的

public getTracks(url?: string): Observable<any> {
return this.http.get(url && url?.length > 0 ? url : `${this.baseSpotifyUrl}/me/tracks?limit=50`);
}

public getAllTracks(): Observable<any[]> {
// the first call is with no parameter so that the default url with no offset is used
return getTracks().pipe(
// expand is used to call recursively getTracks until next is null
expand(data => data.next === null ? EMPTY : getTracks(data.next)),
// with tap you can see the result returned by each call
tap(data => console.log(data)),
// if you want you can use the reduce operator to eventually emit the
// accumulated array with all items
reduce((acc, val) => {
acc = [...acc, ...val.items]
return acc
}, [])
)
}

// now you can fire the execution of the recursive calls by subscribing
// to the observable returned by getAllTracks
getAllTracks().subscribe(
// allItems is an array containing all the items returned by the various calls
allItems => console.log(allItems)
)

@skyleguy 评论后的补充说明

tap 运算符用于实现副作用。换句话说,它从上游接收所有通知,对通知的数据做任何它需要做的事情,然后将相同的通知传递给下游。传递给 tap 操作符的函数不需要返回任何东西。在应用副作用 之后,上游只是传递给下游。在此示例中,副作用只是在控制台上打印随通知传递的数据。

pipe 中使用的 reduce 是 RxJs 的 reduce 运算符,而不是 reduce 方法 数组reduce RxJs 运算符累积从上游通知的所有数据,并在上游完成时发出仅一个值。因此,在这个例子中,每次调用远程函数都会返回一些东西,这个东西会进入 reduce 运算符并参与累加逻辑。当 expand 返回 EMPTY Observable 时,在递归结束时,EMPTY Observable 只是完成而不通知任何东西,这意味着上游 completes 因此 reduce 可以发出它的第一个也是唯一的通知,即包含所有项目的数组,然后 complete .

This stackblitz通过模拟远程调用来复制此逻辑。

关于angular - 使用 RXJS 继续以 Angular 触发 http 调用,直到满足条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68686727/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com