Angular6 下载媒体文件和调度进度的NgRX效果;如何处理流和节流

Angular6 下载媒体文件和调度进度的NgRX效果;如何处理流和节流,angular6,ngrx,ngrx-effects,Angular6,Ngrx,Ngrx Effects,我在理解和应用@Effects作为我的剧集下载选项方面有点困难。我在另一个问题上得到了一些帮助,这是我的最新配方 快速概述:用户单击下载,发送第一个效果中捕获的download\u插曲操作。下载调用返回HttpEvents流和最终HttpResponse 在event.type==3期间,我想报告下载进度。当event.type===4主体到达时,我可以调用success,例如它可以创建一个Blob 服务插曲服务: download( episode: Episode ): Observable

我在理解和应用@Effects作为我的剧集下载选项方面有点困难。我在另一个问题上得到了一些帮助,这是我的最新配方

快速概述:用户单击下载,发送第一个效果中捕获的
download\u插曲
操作。下载调用返回HttpEvents流和最终HttpResponse

event.type==3
期间,我想报告下载进度。当
event.type===4
主体到达时,我可以调用success,例如它可以创建一个Blob

服务<代码>插曲服务:

download( episode: Episode ): Observable<HttpEvent<any>> | Observable<HttpResponse<any>> {

  // const url = encodeURIComponent( episode.url.url );
  const url = 'https%3A%2F%2Fwww.sample-videos.com%2Faudio%2Fmp3%2Fcrowd-cheering.mp3';
  const req = new HttpRequest( 'GET', 'http://localhost:3000/episodes/' + url, {
    reportProgress: true,
    responseType: 'blob'
  } );
  return this.http.request( req );
}

downloadSuccess( response: any ): Observable<any> {
  console.log( 'calling download success', response );
  if ( response.body ) {
    var blob = new Blob( [ response.body ], { type: response.body.type } );
    console.log( 'blob', blob );
  }
  return of( { status: 'done' } );
}

getHttpProgress( event: HttpEvent<any> | HttpResponse<Blob> ): Observable<DownloadProgress> {

  switch ( event.type ) {
    case HttpEventType.DownloadProgress:
      const progress = Math.round( 100 * event.loaded / event.total );
      return of( { ...event, progress } );

    case HttpEventType.Response:
      const { body, type } = event;
      return of( { body, type, progress: 100 } );

    default:
      return of( { ...event, progress: 0 } );
  }
}
你认为这是最好的解决方案吗?类型3和类型4是分开的,我可以控制它

*更新2: 它确实会产生一个问题,即在
下载成功
进度为100%的操作后,可以触发进度为97%的
进度操作。
每次我遇到新的挑战

SampleTime(500)
似乎有效,因为它似乎不会在出现类型4事件之后抛出类型3事件


*更新3:我刚刚发现我现在打了两次电话
Download
,效果是,叹气。我回到原点,试图阻止来自EpicodeService.download的HttpEvent流。

我认为如果您不想使用
if-else
语句,您必须创建不同的效果

在当前操作中,您将使用有效负载中的类型分派一个新操作,例如
downloadEpisodeProges
。 然后,您将创建两个监听此操作的效果,并通过类型对其进行相应过滤,一个效果将用于分派
DownloadProgressSpices
,另一个用于
DownloadSpicesSuccess

另一个可能的解决方案是,但我没有将其与NgRx效果结合使用


记住,对于您进行的每个订阅,都会有性能成本,我个人并不介意
if-else
语句。

我也查看了分区操作符。不确定它是否适用于NGRX,我尝试了,但失败了。但我可以再试一次。我也不介意IF-ELSE,我只想限制为事件类型3调度的操作量。
@Effect()
downloadEpisode$ = this.actions$.pipe(
  ofType<episodeActions.DownloadEpisodes>( episodeActions.DOWNLOAD_EPISODE ),
  switchMap( ( { payload } ) => this.episodesService.download( payload )
    .pipe(
      switchMap( (response: HttpEvent<any> | HttpResponse<any>) => this.episodesService.getHttpProgress( response ) ), //merge in the progress
      map( ( response: fromServices.DownloadProgress ) => {

        // update the progress in the episode
        //
        if ( response.type <= 3 ) {
          return new episodeActions.DownloadProgressEpisodes( { ...payload, download: {
            progress: response.progress
          } }  );

        // pass the Blob on the download response
        //
        } else if ( response.type === 4 ){
          return new episodeActions.DownloadEpisodesSuccess( response );
        }
      } ),
      catchError( error => of( new episodeActions.DownloadEpisodesFail( error ) ) ),
    )
  )
)

@Effect( { dispatch: false } )
processDownloadEpisodeSuccess$ = this.actions$.pipe(
  ofType<any>( episodeActions.DOWNLOAD_EPISODE_SUCCESS ),
  switchMap( ( { payload } ) => this.episodesService
    .downloadSuccess( payload ).pipe(
      tap( response => console.log( 'response', payload,response ) ),

      //  catchError(err => of(new episodeActions.ProcessEpisodesFail(error))),
    )
  )
)
  @Effect( )
  downloadEpisode$ = this.actions$.pipe(
    ofType<episodeActions.DownloadEpisodes>( episodeActions.DOWNLOAD_EPISODE ),
    switchMap( ( { payload } ) => this.episodesService.download( payload )
      .pipe(
        switchMap( (response: HttpEvent<any> | HttpResponse<any>) => this.episodesService.getHttpProgress( response ) ),
        throttleTime( 500 ),
        map( ( response: fromServices.DownloadProgress ) => {
          console.log('Type 3', response);
          // update the progress in the episode
          if ( response.type <= 3) {
            return new episodeActions.DownloadProgressEpisodes( { ...payload, download: {
              progress: response.progress
            } }  );
          }
        } ),
        catchError( error => of( new episodeActions.DownloadEpisodesFail( error ) ) ),
      )
    )
  )

  @Effect( )
  downloadEpisodeLast$ = this.actions$.pipe(
    ofType<episodeActions.DownloadEpisodes>( episodeActions.DOWNLOAD_EPISODE ),
    switchMap( ( { payload } ) => this.episodesService.download( payload )
      .pipe(
        switchMap( (response: HttpEvent<any> | HttpResponse<any>) => this.episodesService.getHttpProgress( response ) ),
        last(),
        map( ( response: fromServices.DownloadProgress ) => {
          console.log('Type 4', response);
          if ( response.type === 4 ){
            return new episodeActions.DownloadEpisodesSuccess( response, { ...payload, download: {
              progress: response.progress
            } } );
          }
        } ),

        catchError( error => of( new episodeActions.DownloadEpisodesFail( error ) ) ),
      )
    )
  )