【问题标题】:Angular wait for multiple asynchronous post request and then call another endpointAngular等待多个异步发布请求,然后调用另一个端点
【发布时间】:2020-10-28 16:45:50
【问题描述】:

我正在使用 Angular 并希望实现以下功能。

用户可以在表单中上传多张图片。在表单提交时,我想用 post 方法调用上传端点的次数与图像的次数一样多(简单的 for 循环)。每次调用都会返回一个响应,其中包含每个图像的谷歌云平台存储链接。每次我都会将链接推送到数组。一旦它遍历所有图像,我想最终提交 post/patch 请求,其中包含表单中的 json 数据和带有指向谷歌云平台链接的数组。

目前我正在努力处理异步代码。我想在最后调用的请求首先被触发,因此带有 GCP 链接的图像数组为空(尽管图像已正确上传到 GCP,但图像的上传发生在文档保存后。从类似的帖子我知道可能会使用 switchMap 但我不知道如何在这种情况下使用它

#update 基于@Picci 评论,适用于一张图片

我必须将 FileList 转换为数组,我用

this.filesListArray = Array.from(this.filesList);

然后实施Picci方案:

 onSave(){
if(this.form.invalid) {
  console.log(this.form)
  return;
}

const uploadRequests$:Observable<[string]> =  this.filesListArray.map(file => 
  from(this.uploadService.upload(file)) // transform Promise to Observable using the rxjs 'from' function
  .pipe(
     map(response => response['filePath']),
     catchError(err => of(`Error while uploading ${file}`))  // if there is an error, return the error
  )
);

const urlsOrErrors$ = forkJoin(uploadRequests$);


urlsOrErrors$.pipe(
  concatMap(result => this.eventsService.update(this.id, this.form.value, result))
).subscribe(() => {
  this.form.reset();
  this.router.navigate([this.id]);
})
.closed;
}

【问题讨论】:

    标签: angular rxjs


    【解决方案1】:

    如果我理解正确,您想先上传图片,然后保存一个 Json,其中包含与上传的图片对应的 url 列表等内容。

    如果是这样的话,那我就这样继续下去。

    首先,我将Promises 转换为Observables 并创建一个Observables 数组,对应于上传文件的请求,类似于这样

    const uploadRequests$ = this.filesList.map(file => 
      from(this.uploadService.upload(file)) // transform Promise to Observable using the rxjs 'from' function
      .pipe(
         map(response => response['filePath']),
         catchError(err => of(`Error while uploading ${file}`))  // if there is an error, return the error
      )
    )
    

    现在您有了一个 Observable 数组,您可以使用 rxjs 的 forkJoin 函数创建一个 Observable,它将并行执行所有上传请求并发出一个包含所有响应的数组。

    考虑到我们构建 Observables 的方式,响应将是上传服务返回的 url 或错误字符串。

    代码类似于

    const urlsOrErrors$ = forkJoin(uploadRequests$)
    

    一旦urlsOrErrors$ 发出,我们就准备执行最后一个服务来保存Json。我们需要确保仅在发出urlsOrErrors$ 时才执行此类服务,因此我们使用concatMap 运算符。

    最终的完整代码如下所示

    const uploadRequests$ = this.filesList.map(file => 
      from(this.uploadService.upload(file)) // transform Promise to Observable using the rxjs 'from' function
      .pipe(
         map(response => response['filePath']),
         catchError(err => of(`Error while uploading ${file}`))  // if there is an error, return the error
      )
    )
    
    const urlsOrErrors$ = forkJoin(uploadRequests$)
    
    urlsOrErrors$.pipe(
      concatMap(urlsOrErrors => this.eventsService.update(
        this.id, 
        this.form.value, 
        urlsOrErrors
      ))
    )
    

    如果您对在异步服务中使用 rxjs 的常见模式感兴趣,您可以找到this article interesting

    【讨论】:

    • 谢谢,我已按照您的建议修复了一张图片。我仍然不知道如何处理文件列表。在您的代码中 this.files.map 引发异常,因为 FileList 对象上没有可行的映射。
    • 好吧,我的错了,代码工作得很好,我只需要将 FileList 转换为文件对象数组
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-01
    • 2023-03-28
    • 2022-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-03
    相关资源
    最近更新 更多