【问题标题】:Angular 6 nested requests dont deliver right dataAngular 6 嵌套请求不提供正确的数据
【发布时间】:2019-07-10 16:14:20
【问题描述】:

我订阅了两个相互嵌套的 httprequest。我的目的是让模型数组在第一个请求中充满对象,而不是发出第二个请求并订阅它,这样我就可以从第一个请求中修改对象。 问题是,在第二个请求中,我正在执行许多对象操作,当我将其保存到存储中时,这些操作不存在..

 private _patientListPoll$ = interval(this.listRequestInterval).pipe(
startWith(0),
map(() => this.getPatientList().subscribe(model=>{
  this.model = model.map(a => Object.assign({}, a));
  const linkedIds = this.model.filter(x => x.linkedUserId && x.statusId === 2).map(x => x.linkedUserId);
  this.deviceDataService.getLastActivity(linkedIds).subscribe(data=>{
    for (const item of data) {
      let patient = this.model.find(x => x.linkedUserId === item.userId);
      if (patient) {
        Object.assign(patient, { lastActivity: item.lastUploadDate });
        const diff = Math.abs(new Date().getTime() - new Date(patient.lastActivity).getTime());
        const diffDays = Math.ceil(diff / (1000 * 3600 * 24));
        if (diffDays <= 7) {
          Object.assign(patient, { filterStatus: 4 });
        }
        let id = patient.id;
        let index = this.model.findIndex(item => item.id === id)
        this.model.splice(index, 1, patient)
        console.log(this.model)
      }
    }
    this.patientDataStore.savePatientData(this.model);
  })

}), share()));

任何想法都会很棒..

在 bryan60 的大力帮助下,我明白了

private _patientListPoll$ = timer(0, this.listRequestInterval).pipe(
switchMap(() => this.getPatientList()),
switchMap(model => {
  const linkedIds = model.filter(x => x.linkedUserId && x.statusId === 2).map(x => x.linkedUserId);
  this.trialService.getPatientTrialStatusList().subscribe(data=>{
    if (data) {
      for (const item of data.result) {
        for (const patient of model) {
          if (item.id === patient.id) {
            Object.assign(patient, {trialStatusId: item.state});
            console.log(patient)
            break;
          }
        }
      }
    }
  })
  return this.deviceDataService.getLastActivity(linkedIds).pipe(
    map(data => {
      for (const item of data) {
        let patient = model.find(x => x.linkedUserId === item.userId);
        if (patient) {
          Object.assign(patient, {lastActivity: item.lastUploadDate});
          const diff = Math.abs(new Date().getTime() - new Date(patient.lastActivity).getTime());
          const diffDays = Math.ceil(diff / (1000 * 3600 * 24));
          if (diffDays <= 7) {
            Object.assign(patient, {filterStatus: 4});
          }
          let id = patient.id;
          let index = model.findIndex(item => item.id === id);
          model.splice(index, 1, patient);
        }
      }
      return model;
    })
  );
}),
tap(model => {
  this.patientDataStore.savePatientData(model);
  this.model = model;
}),
share());

【问题讨论】:

    标签: angular rxjs angular6


    【解决方案1】:

    您现在正在使用导致您的问题的“嵌套订阅”反模式。相反,通过使用适当的高阶可观察对象来避免嵌套订阅。

    private _patientListPoll$ = timer(0, this.listRequestInterval).pipe( // prefer timer to interval and starts with
      switchMap(() => // use switchMap to subscribe to inner observable and cancel previous subscriptions if still in flight
        forkJoin(this.getPatientList(), this.trialService.getPatientTrialStatusList())), //forkJoin runs multiple observables in parrallel and returns an array of the values
      switchMap(([model, trialData]) => { // now I have both model and trial data 
        // this.model = model.map(a => Object.assign({}, a)); don't produce side effects
        use it as needed...
        if (trialData) {
          for (const item of trialData.result) {
            for (const patient of model) {
              if (item.id === patient.id) {
                Object.assign(patient, {trialStatusId: item.state});
                console.log(patient)
                break;
              }
            }
          }
        }
    
        const linkedIds = model.filter(x => x.linkedUserId && x.statusId === 2).map(x => x.linkedUserId);
        return this.deviceDataService.getLastActivity(linkedIds).pipe(
          map(data => { // now do your mapping since you've got both
            for (const item of data) {
              let patient = model.find(x => x.linkedUserId === item.userId);
              if (patient) {
                Object.assign(patient, { lastActivity: item.lastUploadDate });
                const diff = Math.abs(new Date().getTime() - new Date(patient.lastActivity).getTime());
                const diffDays = Math.ceil(diff / (1000 * 3600 * 24));
                if (diffDays <= 7) {
                  Object.assign(patient, { filterStatus: 4 });
                }
                let id = patient.id;
                let index = model.findIndex(item => item.id === id)
                model.splice(index, 1, patient)
                console.log(model)
              }
            }
            return model;
          })
        );
      }),
      tap(model => { // prefer tap for side effects if absolutely necessary
        this.patientDataStore.savePatientData(model);
        this.model = model;
      }),
      share()
    );
    

    这也大大清理了您的管道。

    与手头的问题不严格相关,但您可以稍微清理/简化您的地图逻辑:

      map(data => 
        model.map(patient => {
          let toAssign = {};
          const item = data.find(x => x.userId === patient.linkedUserId);       
          if (item) { 
            const lastActivity = item.lastUploadDate;
            const diff = Math.abs(new Date().getTime() - new Date(lastActivity).getTime());
            const diffDays = Math.ceil(diff / (1000 * 3600 * 24));
            const filterStatus = (diffDays < 7) ? 4 : patient.filterStatus;
            toAssign = {
              lastActivity,
              filterStatus
            };
          }
          const trial = (trialData || []).find(t => t.id === patient.id);
          if (trial) {
            Object.assign(toAssign, {trialStatusId: trial.state});
          }
          return Object.assign({}, patient, toAssign);
        })
      )
    

    【讨论】:

    • 非常感谢您救了我的命。最后一个问题...我需要添加第三个问题“switchMap(() => this.trialService.getPatientTrialStatusList())”和结果,我需要添加患者属性..我应该把最里面的 obeservable 放在哪里?
    • 它是否依赖于其他任何东西? IE 你需要一些来自 getPatientList() 或 getLastActivity() 的信息吗?更新您的问题以尝试准确显示您需要它的位置/原因/时间可能会更好。您想在间隔内请求此数据以及 getPatientList() 吗?还是这些数据本质上更静态?
    • 我更新了代码.. 到目前为止它有效,但我觉得这不是最佳实践.. 有什么想法吗?
    • 绝对不是......你仍然有嵌套的订阅者。只有一个订阅...更新了答案以显示如何。
    【解决方案2】:

    如果可以的话,我会使用评论,但我还没有足够的代表。根据我所见,您有一个错误的),它就在share() 之后,应该在最后一个}) 之后,这可能会导致map 运算符出现问题。

    之前

    ...
    }), share()));
    

    之后

    ...
    })), share()));
    

    程序是否提供任何错误或任何附加信息?推荐使用浏览器调试器下断点,一步步运行函数,看看是怎么回事。

    【讨论】:

      猜你喜欢
      • 2016-09-14
      • 2018-05-04
      • 1970-01-01
      • 2018-09-28
      • 2018-02-14
      • 2018-12-12
      • 2019-02-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多