简体   繁体   English

使用 RxJS pipe() 将数组转换为 Angular 中的异步值的 stream

[英]Use RxJS pipe() to turn array into stream of asynchronous values in Angular

type Movie = {id: string};
type FullMovie = {id: string, picture: string};

I have a url that returns an array of type Movie :我有一个 url ,它返回一个Movie类型的数组:

http.get(url).subscribe(res: Movie[])

I use http.get(movie.id) for each movie in the array returning a FullMovie :我对返回FullMovie的数组中的部电影使用http.get(movie.id)

http.get(movie.id).subscribe(res: FullMovie)

so in essence I want to create a method that returns a stream of FullMovie objects, as the requests resolve: getAll = (url): Observable<FullMovie>所以本质上我想创建一个返回 FullMovie 对象的 stream 的方法,因为请求解决: getAll = (url): Observable<FullMovie>

getAll = (url): Observable<FullMovie> => {
  return http.get(url)
    //must pipe the array into a stream of FullMovies but not a stream of FullMovie Observables. I don't want to subscribe to each of the returned FullMovies
    //something like
   .pipe(//map(array => array.forEach(movie => return http.get(movie.id))))
}

At the moment I have the following solution that works but I want to a more concise solution:目前我有以下可行的解决方案,但我想要一个更简洁的解决方案:

 private getFull = (queryGroup: string): Observable<TMDBMovie> =>
    new Observable<TMDBMovie>((observer) => {
      //get movie array
      this.httpGet(queryGroup).subscribe((movies) => {
        var j = 0;

        if (movies.length === 0) return observer.complete();

        //loop through elements
        movies.forEach(movie => {
          this.getById(movie.id).subscribe(
            (res) => complete(observer.next(res)),
            (error) => complete()
          );
        });
          
        }

        const complete = (arg: any = 0) => {
          if (++j === len) observer.complete();
        };
      });
    });

EDIT:编辑:

I have the following that works perfectly until the http request throws an error then the Observable stops, I think my catchError() is in the wrong place我有以下工作完美,直到 http 请求引发错误然后 Observable 停止,我认为我的catchError()是在错误的地方

newGetFull = (queryGroup: string): Observable<TMDBMovie> =>
    this.httpGet(queryGroup)
      .pipe(map((m) => concat(...m.map((movie) => this.getById(movie.id)))))
      .pipe(switchMap((_) => _))
      .pipe(catchError(() => of()));

So the function emits objects as they are received until a 404 error is thrown then it stops因此,function 在收到对象时发出对象,直到抛出404 error然后停止

You may want to try something along these lines您可能想尝试这些方面的东西

getAll = (url): Observable<FullMovie> => {
  return http.get(url)
   .pipe(
      // turn the array Movie[] into a stream of Movie, i.e. an Obsevable<Movie>
      concatMap(arrayOfMovies => from(arrayOfMovies)),
      // then use mergeMap to "flatten" the various Obaservable<FullMovie> that you get calling http.get(movie.id)
      // in other words, with mergeMap, you turn a stream of Observables into a stream of the results returned when each Observable is resolved
      mergeMap(movie => http.get(movie.id))
   )
}

Consider that using mergeMap as above you do not have guarantee that the final stream will have the same order as the array of Movie s you get from the first call.考虑到使用上面的mergeMap您不能保证最终的 stream 将与您从第一次调用中获得的Movie数组具有相同的顺序。 This is because each http.get(movie.id) can take different time to return and therefore the order is not guaranteed.这是因为每个http.get(movie.id)可能需要不同的时间才能返回,因此无法保证订单。

If you need to guarantee the order, use concatMap rather than mergeMap (actually concatMap is mergeMap with concurrency set to 1).如果需要保证顺序,请使用concatMap而不是mergeMap (实际上concatMap是并发设置为1的mergeMap )。

If you want all the http.get(movie.id) to complete before returning the result, then use forkJoin rather than mergeMap like this如果您希望所有http.get(movie.id)在返回结果之前完成,然后使用forkJoin而不是这样的mergeMap

getAll = (url): Observable<FullMovie> => {
  return http.get(url)
   .pipe(
      // turn the array Movie[] into an array of Observable<Movie>
      map(arrayOfMovies => arrayOfMovies.map(movie => http.get(movie.id))),
      // then use forkJoin to resolve all the Observables in parallel
      concatMap(arrayOfObservables => forkJoin(arrayOfObservables))
   ).subscribe(
      arrayOfFullMovies => {
        // the result notified by forkJoin is an array of FullMovie objects
      }
   )
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM