【问题标题】:Angular 2 foreach executed before array is altered by another functionAngular 2 foreach 在数组被另一个函数更改之前执行
【发布时间】:2017-12-08 21:09:33
【问题描述】:

我在使用数组时遇到了一些问题,我必须在 foreach 中更改并再次使用它。以下是部分代码:

this.selectedDepartementen.forEach(element => {
      this.DepID = element.ID;
      if (this.USERSDepIDs.indexOf(this.DepID) == -1) {
        this.insertDepartementCoupling(this.DepID, this.USERid, this.AJID, res => {
          if (res) {
            this.loading = false;
            return;
          }
          this.removeAllFromArray(this.USERSDepIDs, this.DepID, res => {
            this.USERSDepIDs = res;
          })
        })
      } else
      {
        this.updateDepartementCoupling(this.DepID, this.USERid, this.AJID, res => {
          if (res) {
            this.loading = false;
            return;
          }
          this.removeAllFromArray(this.USERSDepIDs, this.DepID, res => {
            this.USERSDepIDs = res;
          })
        })
      }
    });

如您所见,我是否调用了函数removeAllFromArray 来删除最后使用的DepID。但是 foreach 不会等待那个函数,它只是继续运行。我猜这是一个异步的东西,但我该如何解决呢?

提前致谢!

编辑

为用户 Duncan 添加函数insertDepartementCoupling

async insertDepartementCoupling(DepID, USERid, AJID, callback) {
    var test = await this.departementService.insertDepartementCoupling(DepID, USERid, AJID).subscribe(
      data => this.mockdata = data,
      error => {
        this.showMessage("error", "Departement koppeling niet gelukt!", "Departement koppeling niet gelukt, zie console voor meer informatie.");
        callback(true);
      },
      () => {
        if (this.mockdata._body) {
          this.showMessage("error", "Departement koppeling niet gelukt!", "Contacteer de administrator!");
          callback(true);
        } else {
          this.showMessage("succes", "Departement koppeling geslaagd!", "Gebruiker is gekoppeld aan de departement(en).");
          callback(false);
        }
      });
  }

【问题讨论】:

  • 你能重写你正在使用的其他函数吗?他们正在使用回调,这将很难确保一切都以合理的顺序发生。如果您可以修改它们以返回 Promise,那么代码应该会变得更简单,因为您可以使用 async/await 来扁平化代码。
  • 我可以重写一切。你能给我一个小例子,我可以如何使用 async/await 来扁平化代码吗?

标签: javascript angular typescript asynchronous


【解决方案1】:

如果您更改insertDepartmentCouplingupdateDepartementCoupling 以便它们返回一个promise,而不是回调,该promise 将通过传递给回调的结果进行解析,并且您也对removeAllFromArray 执行相同的操作(是否完全需要异步吗?),然后制作包含您发布的代码async的函数,然后您可以使用类似这样的代码:

for (const element of this.selectedDepartementen) {
    this.DepID = element.ID;
    if (this.USERSDepIDs.indexOf(this.DepID) == -1) {
        if (await this.insertDepartementCoupling(this.DepID, this.USERid, this.AJID)) {
            this.loading = false;
        } else {
            this.USERSDepIDs = await this.removeAllFromArray(this.USERSDepIDs, this.DepID);
        }
    } else {
        if (await this.updateDepartementCoupling(this.DepID, this.USERid, this.AJID)) {
            this.loading = false;
        } else {
            this.USERSDepIDs = await this.removeAllFromArray(this.USERSDepIDs, this.DepID);
        }
    }
}

请注意,使用 typescript 您可以使用 for..of 来迭代数组而不是 forEach 并避免再次回调。

这段代码现在很清楚它是如何执行的,特别是for 循环将一次执行一次迭代,等待一切完成,但它仍然是完全异步的。包含它的函数必须使用 async 关键字声明,并且它本身必须返回一个 Promise,您可以通过 await 或通过 .then() 回调处理。

您的insertDepartementCoupling 函数已经是异步的,并且在内部使用了一个观察者,因此删除回调并返回一个承诺的最简单方法就是在可观察对象上使用toPromise()。该承诺将以最后一个数据值完成,但您可以使用 .then() 获取您想要返回的布尔值:

async insertDepartementCoupling(DepID, USERid, AJID): Promise<boolean> {
    let result = false;
    var test = await this.departementService.insertDepartementCoupling(DepID, USERid, AJID).subscribe(
      data => this.mockdata = data,
      error => {
        this.showMessage("error", "Departement koppeling niet gelukt!", "Departement koppeling niet gelukt, zie console voor meer informatie.");
        result = true;
      },
      () => {
        if (this.mockdata._body) {
          this.showMessage("error", "Departement koppeling niet gelukt!", "Contacteer de administrator!");
          result = true;
        } else {
          this.showMessage("succes", "Departement koppeling geslaagd!", "Gebruiker is gekoppeld aan de departement(en).");
          result = false;
        }
      }).toPromise();
     return result;
  }

或者,您可以尽快将Observable 转换为承诺,然后您就不需要中间变量了:

async insertDepartementCoupling(DepID, USERid, AJID): Promise<boolean> {
    return this.departementService.insertDepartementCoupling(DepID, USERid, AJID).toPromise()
    .then(
      data => {
        this.mockdata = data
        if (this.mockdata._body) {
          this.showMessage("error", "Departement koppeling niet gelukt!", "Contacteer de administrator!");
          return true;
        } else {
          this.showMessage("succes", "Departement koppeling geslaagd!", "Gebruiker is gekoppeld aan de departement(en).");
          return false;
        }
      },
      error => {
        this.showMessage("error", "Departement koppeling niet gelukt!", "Departement koppeling niet gelukt, zie console voor meer informatie.");
        return true;
      });
  }

【讨论】:

  • 非常感谢您!返回的承诺应该只包含真或假,我找不到如何创建它?我将添加函数insertDepartmentCoupling,这样你就可以看到那里发生了什么
  • 你太棒了!!我可以在我所有的回调函数上使用它!非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-28
  • 1970-01-01
  • 2019-10-22
相关资源
最近更新 更多