在 for 循环中使用 Angular HttpClient

Using Angular HttpClient inside for loop

我对 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,并获得回复。但是我不能 return 循环中的任何东西。

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

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)
} 

你可以使用 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
    }
  );
}