首页 > 解决方案 > 当它已经完成以角度获取数据时如何一一显示数据

问题描述

HTML

<div nz-row *ngIf="tempThermometer | async as temp">
<div *ngFor="let data of temp;let i = index;" nz-col nzXs="24" nzSm="12" nzMd="12" nzXl="8" nzXXl="6">
<nz-spin nzTip="Loading..." [nzSize]="'large'" [nzSpinning]="data.spinning">
                            <div echarts [options]="chartOption[i]" [autoResize]="true" style="height: 270px;"></div>
                          </nz-spin>
    </div>
    </div>

TS

 tempLoading = false;
  tempThermometer = new BehaviorSubject<any>([]);

getRoomList() {
    this.tempLoading = true;
    this.subscription = this.global
      .getData(`/conditions/latest?length=${this.pageSize}`)
      .pipe(take(1))
      .subscribe((res: any) => {
        this.tempThermometer.next(Object.values(res['data'].map((obj: any) => {
          return {
            ...obj,
            spinning: true
          };
        })));

        this.tempLoading = false;
        this.lineChart(this.tempThermometer.value);
      });
  }
lineChart(params?: any) {
    const _this = this;
    const list: any = [];

    params.forEach((param: any) => {
      const url = encodeURIComponent(param.sensor);
      // List URL
      list.push(`/conditions?length=${this.length}&sensor=${url}`);
    });
    // Promise requests
    const promises = list.map(
      (url: any) =>
        new Promise(resolve => {
        this.subscription =  this.global.getData(url).pipe(take(1)).subscribe((res) => {
            resolve(res);
          }, (err: Error) => {
            return reject(err);
          });
        })
    );
    // Retrieve each data as per promise
    Promise.all(promises).then(results => {
      const dataRoom: any = [];

      results.map((result) => {
        const date: any = [], temperature: any = [], humidity: any = [], newRoomData: any = [];
        const param = result['data'];
        const roomData = orderBy(param, ['date'], ['asc']);
        const room = roomData.slice(-1)[0];
        const timeEnd = room.date.slice(0, 19);
        const timeStart = subHours(timeEnd, 7);
        const dataHour = roomData.filter((data: TemplogRecord) => {
          return !isBefore(data.date, timeStart) && !isAfter(data.date, timeEnd);
        });

        // console.log(roomData);

        const hash = Object.create(null);

        dataHour.forEach((data: any) => {
          const key = data.date.slice(0, 13);

          if (!hash[key]) {
            hash[key] = {
              sensor: data.sensor, temperature: data.temperature,
              humidity: data.humidity, date: key + ':00:00'
            };
            newRoomData.push(hash[key]);
          }
        });

        for (let x = 0; x < newRoomData.length; x++) {
          temperature.push(newRoomData[x].temperature);
          humidity.push(newRoomData[x].humidity);
          date.push(newRoomData[x].date);
        }

        dataRoom.push({
          date: date,
          humidity: humidity,
          temperature: temperature
        });
      });

      dataRoom.forEach((param: any, index: number) => {
        const option = {
          tooltip: {
            trigger: 'axis',
            axisPointer: {
              animation: false
            },
            backgroundColor: 'rgba(245, 245, 245, 0.8)',
            borderWidth: 1,
            borderColor: '#ccc',
            padding: 10,
            textStyle: {
              color: '#000'
            },
            formatter: function (prm: any) {
              let rec = prm[0].name.slice(0, 10) + '<br/>' + prm[0].name.slice(11, 19) + '<br/>';

              for (let x = 0; x < prm.length; x++) {
                if (prm[x].axisIndex !== 1) {
                  rec += prm[x].marker + ' ' + prm[x].seriesName + ': '
                    + prm[x].data + _this.units['Celcius'] + '<br/>';
                } else {
                  rec += prm[x].marker + ' ' + prm[x].seriesName + ': '
                    + prm[x].data + '%' + '<br/>';
                }
              }
              return rec;
            }
          },
          ...this.echart.roomChart,
          dataZoom: [{
            type: 'inside',
            show: false,
            bottom: 0,
            width: '84%',
            xAxisIndex: [0, 1],
            zoomOnMouseWheel: false,
          },
          {
            type: 'slider',
            bottom: 0,
            show: false,
            width: '84%',
            xAxisIndex: [0, 1],
            zoomLock: false,
          }],
          xAxis: [{
            type: 'category',
            boundaryGap: false,
            scale: true,
            axisLine: {
              show: false
            },
            axisTick: {
              show: false
            },
            data: param.date.map((str: any) => {
              return format(str, 'YYYY-MM-DD hh:mm a');
            }),
            splitLine: {
              show: true,
              lineStyle: {
                color: 'rgba(182, 202, 227)'
              }
            },
            axisLabel: {
              show: true,
              interval: 0,
              rotate: 90,
              formatter: ((data: any) => {
                return (data).slice(11, 19);
              })
            }
          },
          {
            gridIndex: 1,
            show: false,
            scale: true,
            type: 'category',
            boundaryGap: false,
            axisLine: {
              show: false
            },
            data: param.date,
            axisTick: {
              show: false
            },
            splitLine: {
              show: true
            }
          }],
          series: [{
            name: 'Humidity',
            data: param.humidity,
            type: 'line',
            itemStyle: {
              color: 'rgba(0, 101, 144, 1)'
            },
            markPoint: {
              type: 'Pin',
              data: [
                {
                  type: 'max',
                  itemStyle: {
                    color: 'rgba(0, 101, 144)'
                  }
                },
                {
                  type: 'min',
                  itemStyle: {
                    color: 'rgb(110, 151, 204)'
                  }
                }
              ]
            },
            smooth: true,
            xAxisIndex: 1,
            yAxisIndex: 1
          },
          {
            name: 'Temperature',
            data: param.temperature,
            type: 'line',
            itemStyle: {
              color: 'rgba(255, 0, 0, 1)'
            },
            markPoint: {
              type: 'Pin',
              data: [
                {
                  type: 'max',
                  itemStyle: {
                    color: 'rgba(255, 5, 0)'
                  }
                },
                {
                  type: 'min',
                  itemStyle: {
                    color: 'rgb(255, 87, 86)'
                  }
                }
              ]
            },
            smooth: true
          },

          ]
        };
        this.chartOption.push(option);
        this.notScrolly = true;
        this.tempThermometer.value.filter((x: any) => params.map((y: any) => {
          if (y.id === x.id) {
            return y.spinning = false;
          }
        }));
      });
    });
  }

这里的问题是,当它加载时,它会在显示所有数据之前获取所有数据。我在这里要做的是,当第一个项目已经获取时,它将显示,而其他项目仍在获取数据。

例如有 5 个项目,即区域 1、区域 2、区域 3、区域 4 和区域 5。

当区域 1 已经完成获取数据时,它将显示它。而另一个仍在加载/获取。

就像区域 1 已经完成获取,然后是区域 3,然后是区域 2,然后是区域 5,然后是 4。

谁完成获取它会自动显示。

标签: javascriptangulartypescript

解决方案


我会以两种方式之一来解决这个问题。两者都不会涉及承诺。

我不会尝试使用您的代码示例,因为它太大了,相反,我将专注于您的问题的核心 - 运行一组可观察对象并在返回结果时对其进行处理。

1. 合并 observables

RxJSmerge函数将一起运行多个 observable,并立即使用各个值调用您的订阅回调。

const observables: Observable<any>[] = this.getObservables();
merge(...observables).subscribe(result => {
  // individual results are logged here as soon as the observable returns them
  console.log(result);
}, err => {
  // empty error callback. 
  // This is here to allow us to add the complete callback
}, () => {
  console.log('complete');
});

优点:订阅结果处理简单

缺点:必须在完整的回调中运行完整的代码

2.管道中的处理结果

您可以在forkJoin. 只有在最终的 observable 完成时才会调用 subscribe,但您可以在单个tap运算符中处理结果。

const observables: Observable<any>[] = this.getObservables()
  .map(x => x.pipe(
    // tap is run as soon as the observable is returned
    tap(result => console.log(result))
  ));
forkJoin(observables).subscribe(result => {
  console.log('complete');
});

Pro:订阅中的简单完整处理

单个运算符中的Con处理结果tap可能会有点混乱

结论

这两种方法是相当等价的。我可能更喜欢这种forkJoin方法,但我想通过给你第二个例子来展示 RxJS 的强大和灵活性。

演示:https ://stackblitz.com/edit/angular-7rrmtn

该演示设置了 5 个可观察对象,每个对象都有不同的延迟。在返回结果时处理 observables,并在完成时记录它们。

如您所见,它们在功能上是等效的。


推荐阅读