【问题标题】:RxJs Angular 7 HttpClient multiple POST with forkJoin remove second subscribe?带有forkJoin的RxJs Angular 7 HttpClient多个POST删除第二个订阅?
【发布时间】:2019-05-03 13:24:03
【问题描述】:

我正在创建一个带有链接子任务对象的工作项对象。我的函数 (createWorkItemAndChildren) 有两个参数,workItem 和一个 Task 对象数组。我希望我的函数返回一个包含所有创建的 ID(工作项和任务)的数组。

我必须从一个 http POST 调用 (workItemService.createWorkItem) 中获取父 ID,然后才能创建在同一服务上使用另一个 http POST 方法的子任务。

我现在在 createChildWorkItems 中有 forkJoin 一次返回所有子 ID。

我如何重构它以便只有一个订阅,并一起返回包含父 ID 和子 ID 的数组?

  createChildWorkItems(parentId, tasks: Task[]): Observable<any> {
    return <Observable<number>> forkJoin(
      tasks.map(task => <Observable<number>> this.workItemService.createChildWorkItem(parentId, task))
    ).pipe(zip());

  }

  createWorkItemAndChildren(workItem, childTasksToSave: Task[]){
    var resultArray = [];
    this.workItemService.createWorkItem(workItem).subscribe(workItemId => {
      var parentId = workItemId;
      resultArray.push(parentId);
      if (parentId !== null){
        this.createChildWorkItems(parentId, childTasksToSave).subscribe((results: number) => {
          resultArray.push(results);
          this.tfsIdsCreated = resultArray;
        });
      }
    });
  }

【问题讨论】:

    标签: angular loops rxjs observable


    【解决方案1】:

    在您的情况下,孩子不是 fork join 的好人选。但在这里你应该使用异步/等待。 fork join 以异步方式发送请求,但 Async/await 将等待每个请求的响应,当您获得响应时,将该响应附加到父简单, 在 Async/await 中的请求将像循环一样按顺序排列。当所有请求完成后,返回该对象 这是 asyn/await https://lavrton.com/javascript-loops-how-to-handle-async-await-6252dd3c795/ 的链接

      createWorkItemAndChildTasks(workitem, childTasksToSave: Task[]): any {
        this.workItemService.createWorkItem(workitem).subscribe(workItemId => {
         var parentId = workItemId;
          if (parentId !== null ){
            this.tfsIdsCreated.push(parentId);
    
        // now create the children on the workItemForm.
        for (let child of childTasksToSave){
    //use here Async await when you get response attach to parent 
    
         this.workItemService.createChildWorkItem(parentId, child).subscribe(task =>{
            if (task !== null){
              console.log(' createWorkItem received child taskid: ' + task);
              this.tfsIdsCreated.push(task);
            }
          });
        }
      }
      return this.tfsIdsCreated;
    });
    

    }

    【讨论】:

    • 异步等待的语法如何变化?
    • 向 createWorkItemAndChildTasks 添加 async 关键字 试试这个 .. async createWorkItemAndChildTasks(workitem, childTasksToSave: Task[]){ // for (let child of childTasksToSave){ const task = fetchChild(parentId, child); if (task !== null){ console.log(' createWorkItem received child taskid: ' + task); this.tfsIdsCreated.push(task); } } } async fetchChild(parentId, child){ const response = await this.workItemService.createChildWorkItem(parentId, child).toPromise();返回响应;
    【解决方案2】:

    如果您想并行执行子任务 - forkJoin 是您的选择。

    这是一个粗略的例子:

    createParent().pipe(
      // switch from parent stream to forkJoin(...children)
      mergeMap(parent =>
        // wait for all children to be created
        forkJoin(children.map(child => createChild(parent, child))).pipe(
          // combine childResults with parent
          map(childResults => {
            // do operations with parent and all children
            parent.childResults = childResults;
            // switch back to parent
            return parent;
          })
        )
      )
    )
    .subscribe(parent => {
      // ...
    })
    

    注意我们如何只订阅 Observable 一次——这是一个很好的做法。

    这里不需要async await

    希望对你有帮助

    【讨论】:

    • 我很欣赏这个建议,但我在理解如何使我的代码适应这个问题时仍然遇到一些问题。在您的 createParent() 示例代码中,是返回一个 observable 还是只是一个数字?
    • @JenniferS, createParent() 应该返回 Observable,类似于您的 this.workItemService.createWorkItem。在这里,我编译了一个小例子,更接近你的代码:mergeMap with forkJoin
    • 感谢您的额外解释。但是 rxObserver 在做什么呢?
    • @JenniferS 它是图表 API 的一部分,用于渲染这些大理石图。它实现了Observer接口,所以如果你想让它输出到控制台,你可以用x=&gt;console.log(x)代替它。
    • @JenniferS,很高兴听到这个消息 :) GL
    【解决方案3】:

    创建一个 observables 数组并将引用传递给 forkjoin

    let observableBatch= [];
    
    for (let child of childTasksToSave){
       observableBatch.push(this.workItemService.createChildWorkItem(parentId, child));
    }
    
    Observable.forkJoin(observableBatch).subscribe...;
    

    参考: https://stackoverflow.com/a/35676917/6651984

    【讨论】:

      【解决方案4】:

      这就是我最终做的事情,这就是我接受 kos 答案的原因: 我的 tfsIdsCreated 数组订阅了提供 id 列表的结果。

      createParentAndKids(workItem, childTasksToSave){
          this.workItemService.createWorkItem(workItem).pipe(
            mergeMap(parentId => {
              if (parentId === null){
                return of([parentId]);
              }
      
              const childTaskObservables$ = childTasksToSave.map(
                child => this.workItemService.createChildWorkItem(parentId, child)
              );
      
              return forkJoin(childTaskObservables$).pipe(
                map(ids => [parentId, ...ids])
              );
      
            })
          ).subscribe(x => this.tfsIdsCreated.push(x));
        }
      

      【讨论】:

        猜你喜欢
        • 2018-12-11
        • 2019-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-27
        • 2018-09-21
        • 1970-01-01
        相关资源
        最近更新 更多