【问题标题】:Using Angular HttpClient inside for loop在 for 循环中使用 Angular HttpClient
【发布时间】:2020-06-02 11:43:51
【问题描述】:

我对 Angular 的 HttpClient 有一些问题:

因此,应用逻辑如下所示: component.ts:

我需要从服务中调用 createNewVideoUploadId() 来获取上传视频的 ID。比我需要将文件发送到服务方法:

uploadVideoToApi() {
    this.lessonService.createNewVideoUploadId()
        .subscribe(res => {
            this.lessonService.uploadNewVideo(this.videoToUpload, res['X-Upload-File-ID'])
        })
}

lessonService 看起来像:

createNewVideoUploadId() {
    return this.http.get<string>(`${environment.apiUrl}/upload/id`)
}

上传新视频:

uploadNewVideo(video: File, id: string) {

    const chunkSize = 10 * 1024 ** 2;
    const count = Math.ceil(video.size / chunkSize);

    let calls = []

    for (let i = 0; i < count; i++) {
        let chunk = video.slice(i * chunkSize, (i + 1) * chunkSize);

        let fd = new FormData();
        fd.append('file', chunk);
        fd.append('file_name', video.name);
        fd.append('file_size', video.size.toString());
        fd.append('chunk_size', chunkSize.toString());
        fd.append('chunk_number', i.toString());
        fd.append('chunks_count', count.toString());

        return this.http.post(`${environment.apiUrl}/upload/${id}`, fd)
    }
} // uploadNewVideo()

因此,for 循环在第一次迭代中停止,因为 return

我需要从component.ts一个一个地执行每个for循环迭代

所以,我需要订阅uploadNewVideo,并获得回复。但我不能从循环中返回任何东西。

【问题讨论】:

    标签: angular httpclient


    【解决方案1】:

    你可以使用 RxJS forkJoin() 方法。试试下面的

    uploadNewVideo(video: File, id: string) {
      const chunkSize = 10 * 1024 ** 2;
      const count = Math.ceil(video.size / chunkSize);
      let calls = []
    
      for (let i = 0; i < count; i++) {
        let chunk = video.slice(i * chunkSize, (i + 1) * chunkSize);
    
        let fd = new FormData();
        fd.append('file', chunk);
        fd.append('file_name', video.name);
        fd.append('file_size', video.size.toString());
        fd.append('chunk_size', chunkSize.toString());
        fd.append('chunk_number', i.toString());
        fd.append('chunks_count', count.toString());
    
        calls.push(this.http.post(`${environment.apiUrl}/upload/${id}`, fd).pipe(retry(3)))   // <-- retry 3x in case of error
      }
    
      return forkJoin(calls);     // <-- use `forkJoin` here
    }
    

    现在您可以订阅触发调用的函数

    uploadVideoToApi() {
      this.lessonService.createNewVideoUploadId().pipe(
        switchMap(res => this.lessonService.uploadNewVideo(this.videoToUpload, res['X-Upload-File-ID'])),
        catchError(error => of(error))
      ).subscribe(
        response => {
          // handle response
        },
        error => {
          // handle error
        }
      );
    }
    

    【讨论】:

    • 是的,但是 forkJoin 在 for 循环结束后返回每个值?我需要处理每个请求,如果块丢失,请重新发送。
    • forkJoin 处理每个请求,并且仅当所有可观察对象都完成时才会发出值。如果您需要在失败的情况下重新发送请求,您可以为每个 HTTP POST 请求输入retry 运算符。如果合适,您也可以使用retryWhen。如果 POST 请求失败,我已修改答案以重试三次。
    【解决方案2】:

    只需将 http-post 流存储在一个数组中并连接 thoose:

    uploadNewVideo(video: File, id: string) {
    
        const chunkSize = 10 * 1024 ** 2;
        const count = Math.ceil(video.size / chunkSize);
    
        let calls = []
        let httpCalls = [];
    
        for (let i = 0; i < count; i++) {
            let chunk = video.slice(i * chunkSize, (i + 1) * chunkSize);
    
            let fd = new FormData();
            fd.append('file', chunk);
            fd.append('file_name', video.name);
            fd.append('file_size', video.size.toString());
            fd.append('chunk_size', chunkSize.toString());
            fd.append('chunk_number', i.toString());
            fd.append('chunks_count', count.toString());
    
            httpCalls.push(this.http.post(`${environment.apiUrl}/upload/${id}`, fd));
        }
    
        return concat(httpCalls)
    } 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-02
      • 1970-01-01
      • 2020-09-19
      • 1970-01-01
      • 1970-01-01
      • 2015-01-28
      相关资源
      最近更新 更多