【问题标题】:How does the catch method get called when chaining HTTP promises?链接 HTTP 承诺时如何调用 catch 方法?
【发布时间】:2018-03-14 13:59:37
【问题描述】:

我为我的 Angular 应用程序创建了一个自定义 loaderService,它在后端处理请求(或一组请求)时提供加载微调器。这是我的代码:

export class ComponentOne {
  constructor(loaderService: LoaderService, orderService: OrderService) {}
  ...
  ...
  method() {
    this.loaderService.display(true);
    this.orderService.firstRequest()
      // the misspelled word causes a 500 error
      .then((response) => this.orderService.methodWithWrongInput('misspelled_word'))
      // but it still executes the following then
      .then(() => this.method2())
      .catch(() => null)
      .then(() => this.loaderService.display(false));
  }
  ...
}

我在请求之前显示微调器,但无论请求成功还是失败,我都想确保关闭它。这就是为什么我在底部放一个catch 和最后一个then。代码运行良好,但是当我调试它时,我意识到即使第二个请求(故意拼错的单词)失败,method2() 仍然被调用。还是真的失败了?

我的问题是,catch 方法在链接请求时如何工作。我以为如果请求失败,我们直接去 catch 方法,但我可能错了。

编辑: 原来我对 method2() 的调用是错误的。见 T.J.克劳德的回答更多。

【问题讨论】:

  • 隐藏.finally()块中的微调器。
  • "...我意识到即使第二个请求(故意拼错单词)失败,method2() 仍然被调用。" 不,它肯定会如果methodWithWrongInput 抛出或返回最终拒绝的承诺,则不是。 (请注意,显示的代码缺少)。)不会调用包含method2then 处理程序;后面的catch 会是。
  • @Sajal:标准承诺没有.finally(目前)。这个.catch(...).then(...) 成语是在没有人的情况下处理finally 情况的经典方法。
  • @T.J.Crowder 嗯,那我可能错了……那是不是意味着一旦请求失败,catch 方法就会被调用?
  • @T.J.Crowder,明白了。我通常使用rxjs/Observable,它有finally 块。

标签: angular http typescript promise


【解决方案1】:

...我意识到即使第二个请求(故意拼错单词)失败,method2() 仍然被调用...

我怀疑您误解了您在调试器中看到的内容,在这种情况下很容易做到。

在这段代码中:

method() {
  this.loaderService.display(true);
  this.orderService.firstRequest()
    // the misspelled word causes a 500 error
    .then((response) => this.orderService.methodWithWrongInput('misspelled_word'))
    // but it still executes the following then
    .then(() => this.method2())
    .catch(() => null)
    .then(() => this.loaderService.display(false));
}

会发生什么:

  1. this.loaderService.display(true); 运行
  2. this.orderService.firstRequest() 运行并返回一个承诺
  3. .then((response) => this.orderService.methodWithWrongInput('misspelled_word')) 运行 - 不是回调中的部分,只是 then。它在 Promise 上注册一个解析处理程序并返回一个新的 Promise。
  4. .then(() => this.method2()) 运行——再次,只是 then 调用,而不是它的回调。它返回另一个新的承诺。
  5. .catch(() => null) 运行 - 再次,只是 catch 调用,而不是它的回调。它返回另一个新的承诺。
  6. .then(() => this.loaderService.display(false)) 运行 - 再次,只是 then 调用,而不是它的回调。它返回另一个新的承诺。

然后稍后,来自firstRequest() 的承诺解决,并且

  1. (response) => this.orderService.methodWithWrongInput('misspelled_word') 运行并返回一个新的承诺

然后稍后,该承诺拒绝,并且

  1. () => null(在您的 catch 处理程序中)运行并返回 null,它解决了相关的承诺(例如,将拒绝转换为解决方案)
  2. () => this.loaderService.display(false) 运行,因为此时链已解决(未拒绝)(感谢上面的#8)

因此,在调试器中,您将看到执行光标跨过thenmethod2 的调用,在上面的初始序列(#4)中同步设置链;但这只是将处理程序添加到链中。您不会看到method2 实际被调用,因为当解决/拒绝发生时(在methodWithWrongInput 拒绝的情况下)不会触发回调

【讨论】:

  • 值得注意的是,在提供的示例中调用的 .catch() 方法将恢复承诺链,这解释了为什么 this.loaderService.display(false) 启动以及作者是否想要为了捕捉最终的异常,他希望将 Promise 链包装在 Promise.all();
  • 非常感谢!我一直很难理解 Promise 是如何异步工作的,这无疑带来了一些清晰性。
  • @VadimG 你到底是什么意思?
  • @BobbyBrown - 他的意思是我可能应该强调,通过从catch 处理程序返回一个值,您将拒绝转换为解决方案。我想你知道,但他就是这么说的。我已经添加了一些来解决它。
  • @BobbyBrown,除了 T.J. Crowder 的解释 我想强调的是,链块中的捕获不是通用的。它不会在this.orderService.firstRequest() 中捕获异常。想象一下,有十几个承诺链——对于每个承诺,您都需要拥有自己的捕获,除非您将它们全部包装在一个承诺中并改为捕获它。它可能会在现实世界的应用程序中省去一些麻烦。
猜你喜欢
  • 2021-10-17
  • 2020-04-24
  • 1970-01-01
  • 2019-05-24
  • 1970-01-01
  • 2019-10-07
  • 1970-01-01
  • 2016-11-23
  • 2019-09-29
相关资源
最近更新 更多