首页 > 解决方案 > Angular 6 嵌套请求不提供正确的数据

问题描述

我订阅了两个相互嵌套的 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());

标签: angularrxjsangular6

解决方案


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

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

推荐阅读