【问题标题】:Router navigate immediate execution in async/await method路由器在 async/await 方法中导航立即执行
【发布时间】:2020-06-08 06:37:06
【问题描述】:

我有 组件 A,它具有 异步方法 abc()。在此方法中,我正在等待 service X 中的另一个 async 方法 xyz()。在这个 xyz() 方法中,我有另一个等待调用(我需要按顺序执行调用并在下一个请求中使用响应)。如果在两个特定调用中出现负面结果,我可能会将用户重定向到两个页面之一(目前假设这只是一个页面)。我正在使用router.navigate(['/error']),但它没有像我预期的那样工作......我希望它会停止进一步执行代码并立即执行重定向。

x.service.ts

async ngOnInit() {
   await this.abc();
}

async abc(): Promise<any> {
   await this.serviceX.xyz();

   // below calls are still executed even if we entered the navigation line in xyz() method
   await this.service3.magicMethod();
   await this.service4.anotherMethod();
}

a.component.ts

async xyz(): Promise<any> {
   const result = await this.service1.getData(); // 
   if (result !== 'OK') {
      this.router.navigate(['/error']);
   }

   const userAnswer = await this.service2.userSelection();
   if (userAnswer !== 'OK') {
      this.router.navigate(['/error']);
   }
}

service1 和 service2 都具有异步功能,我正在等待使用 toPromise() 的 HTTP 响应。类似的东西:

async getData(): Promise<SomeResponse> { // or userSelection()
   const response = await this.wrapperService.getHttpResponse().toPromise();
   console.log(response);
   return response as SomeResponse;
}

【问题讨论】:

  • 你能解释一下“不工作”是什么意思
  • 您确定结果不是“OK”并且从未输入条件句?
  • @KurtHamilton,我已经用这句话更新了我的帖子 - “我希望它会停止进一步执行代码并立即执行重定向。”这不会发生,因为正如我在代码的注释部分中提到的那样。
  • @AdamDunkerley 是的,我在这里发帖之前检查过:)

标签: angular typescript async-await routes


【解决方案1】:

如果您希望处理停止,那么您需要告诉它停止。除非另有说明,否则调用的函数 router.navigate 将继续处理。

在您的情况下,您似乎正在服务中执行路由,这会将 UI 问题泄漏到您的服务层中。我会重构您的服务方法以返回指示成功或失败的结果。然后您的组件可以选择导航或继续处理。

service.ts

async xyz(): Promise<boolean> {
   const result = await this.service1.getData(); // 
   if (result !== 'OK') {
       // no further processing
      return false;
   }

   const userAnswer = await this.service2.userSelection();
   if (userAnswer !== 'OK') {
      // no further processing
      return false;
   }

   return true;
}

component.ts

async ngOnInit() {
   await this.abc();
}

async abc(): Promise<any> {
   const success = await this.serviceX.xyz();
   if (!success) {
     this.router.navigate(['/error']);
     // no further processing
     return;
   }

   await this.service3.magicMethod();
   await this.service4.anotherMethod();
}

在您致电 router.navigate 后,我已添加 return; 语句以停止进一步处理。

如果您需要从您的服务返回更多关于真/假的信息,那么您可以返回错误消息或某种对象。一个布尔值足以解释这个概念。

编辑:

很明显,如果您真的想要在服务中执行路由,那么没有什么可以阻止您在那里执行此操作。您仍然会遵循这种返回成功结果的模式,只是现在在每个 return false; 语句之前在服务中进行导航。

编辑 2:

正如我们在 cmets 中所讨论的,我并不是要在这里决定您的设计决策,而只是建议您如何解决问题的模式。

返回错误结果并将结果映射到路径会产生更多开销,但为了清晰起见,我个人仍然更喜欢将路由与数据调用混合使用。我想到了意大利面条代码这句话......

我将采用一种方法来保持服​​务调用和路由分离的示例。这只是一个模式的演示,而不是生产就绪的代码,但希望能给你一些想法。我不介意多打字以换取更简洁的设计。

service.ts

export enum XyzError = { ErrorA = 1, ErrorB = 2 }

async xyz(): Promise<XyzReason> {
   const result = await this.service1.getData(); // 
   if (result !== 'OK') {
       return XyzReason.ErrorA;
   }

   const userAnswer = await this.service2.userSelection();
   if (userAnswer !== 'OK') {
      return XyzReason.ErrorB;
   }

   return null;
}

component.ts

async abc(): Promise<any> {
   const result: XyzReason = await this.serviceX.xyz();
   switch (result)  {
     case XyzReason.ErrorA:
       this.router.navigateByUrl('/errora');
       return;
     case XyzReason.ErrorB:
       this.router.navigateByUrl('/errorb');
       return;
   }

   await this.service3.magicMethod();
   await this.service4.anotherMethod();
}

【讨论】:

  • 好吧,但是在代码的注释部分执行调用之前,我是否需要在我的组件中处理此响应?我尝试了您的解决方案,但仍执行注释代码行中的调用。让我用注释的代码行更新该部分以获得更好的解释。
  • 调用的顺序有点混乱,因为我认为它们被错误地标记了。你能提供一个stackblitz吗
  • 如果我理解你的代码正确,你的服务正在做路由?如果是这种情况,那么我觉得这是一个糟糕的设计选择。我认为路由不应该发生在数据服务中,应该重构服务以返回某种指示失败或成功的结果
  • 我稍后会尝试提供。现在我可以说首先我们调用abc(),然后是xyz(),它执行getData()userSelection()。在 KO 响应的情况下,我想执行立即重定向。而不是它,magicMethod()anotherMethod() 也被执行。这不是我想要的。我想停在xyz() 并重定向。
  • 我完全同意你关于编程的说法。关于您添加的示例,我正在考虑类似的事情。感谢您的帮助。
猜你喜欢
  • 2021-10-28
  • 2020-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多