Angular 订阅填充后调用函数

Angular calling a function once the subscription has populated

无法为视图逻辑获取正确的值。

基本上服务被调用,它运行并填充一个数组,然后我需要它在数组代码完成时调用一个私有函数。

calculateSemesterGPA(semesterId: string, userId: string) {

let gradesArr = [];
let resultsArr = [];
let result;

this.getSemesterGrades(semesterId).valueChanges()
.subscribe(snapshots => {
  snapshots.forEach(snapshot => {
    gradesArr.push(snapshot.grade)  
  });
});

this.getScales(userId).valueChanges()
.subscribe(snapshots => {
  snapshots.forEach(snapshot => {
    for(let i = 0; i < gradesArr.length; i++) {
      if(gradesArr[i] === snapshot.letter) {
        resultsArr.push(snapshot.points);
      }
    }
    result = this.CalculateGPA(resultsArr)
  });
})

return result;

}

/*
    Function to calculate the gpa score of an array passed in.
*/
private CalculateGPA(gradePoints: number[]) {

    let length = gradePoints.length;
    let total = 0;

    for(let i = 0; i < length; i++) {
      total += (gradePoints[i]*1);
    }

    // returns the total grade score divided by the amount of grades in the array.
    console.log(total / length)
    return (total / length);
}

我知道私有函数工作正常,因为它 console.log 的值是正确的。但似乎原始函数在不等待 this.getScales 部分完成的情况下返回结果。我也尝试过直接从该部分内部返回。

您 return 在您的 subscription 之外,因此当您的 subscription 正在获取数据并进行计算时,您已经 return 了。返回订阅内部也不是一个好主意。您希望在哪里看到 return?什么是 valueChanges()。一个subscribe将return一个Subscription。你为什么不把 result 作为一个 class 变量并在你的订阅中像这样直接分配它:

this.result = this.CalculateGPA(resultsArr);

现在,如果您真的必须 return 从您的那个方法,那么不要 subscribe 而是做一个 map 和:

return this.getScales(userId).valueChanges().map(() => {
    ...
    return result
    ...
})

然后您必须 subscribe 到 returned 值。

编辑

我刚刚看到您将订阅一个接一个地放在一种方法下:calculateSemesterGPA(semesterId: string, userId: string) {}。 我们无法判断哪个订阅会先成功。请将第二个订阅嵌套在第一个订阅之下,以便您真正确定,第二个订阅仅在第一个订阅完成后运行。

this.getSemesterGrades(semesterId).valueChanges()
   .subscribe(snapshots => {
      snapshots.forEach(snapshot => {
         gradesArr.push(snapshot.grade)  
      });

      this.getScales(userId).valueChanges()
        .subscribe(snapshots => {
          snapshots.forEach(snapshot => {
          for(let i = 0; i < gradesArr.length; i++) {
            if(gradesArr[i] === snapshot.letter) {
              resultsArr.push(snapshot.points);
            }
          }
         this.result = this.CalculateGPA(resultsArr)
         });
        })    
   });