首页 > 解决方案 > 每个 Promise-chain -> try/catch/await 指南都在教导危险的约定吗?

问题描述

我见过的从捕获错误的 Promise 链到 try/catch/await 的每个示例都如下所示:

class Api {
  static getUserPhones(userObj) {
    console.log(userObj.phones.length)
    return new Promise((resolve, reject) => reject('err'))
  }
}
const user = { id: 123, phones: [] }

/** Turn this... */
Api.getUserPhones(user.id) // user.id is a mistake
 .then(resp => console.log(resp))
 .catch(err => console.error('network error:', err))

/** ...into this! */
try {
  const resp = await Api.getUserPhones(user.id) // user.id is a mistake
  console.log(resp)
} catch (err) {
  console.error('network error:', err)
}

但这在最坏的情况下是不安全的,并且充其量是为我们设置错误。任何可能发生在传递给它的参数 ( ) 内或什至中的任何TypeError, ReferenceError, SyntaxError,等都会意外地被吞入块中。除非您的代码始终没有错误,否则将您的代码转换为与示例类似的代码可能会使查找错误和调试它们变得非常具有挑战性。RangeErrorApi.getUser()user.wrong.idtrytry/catch

举个极端的例子,如果指南告诉我们将您的所有代码放在一个try. 一切都可以抛出,即使不是设计为,我们应该只try在我们的代码按设计抛出时使用。

我错过了什么吗?每个人都只是在编写风险更高的代码而不自知吗?

标签: javascriptnode.jsasync-awaitpromisetry-catch

解决方案


两个代码片段在行为上并不总是 100% 相同的事实并不会使它们中的任何一个都不安全。它只是使它们在特定的边缘情况下有所不同。最后,作为代码作者,是否需要保留这种边缘情况是您的决定。

也就是说,适当的等价物只会在 try/catch 之外获得承诺:

const promise = Api.getUser(user.id)
try {
  const resp = await promise
  console.log(resp)
} catch (err) {
  console.error(err)
}

但是,从这里我们可以根据我们可以做出的假设进行一些修改。例如,如果我们知道它Api.getUser(user.id)不会抛出,那么Api.getUser(user.id)try块内调用是完全有效的。

作为未成年人,我还想就这个问题发表评论:

假设 Api.getUser() 中的所有内容都将永远不会出现 javascript 错误,这是非常愚蠢的

这是一个强有力的断言,它也恰好是明显错误的。首先,让我们明确一点,并非内部的所有内容都Api.getUser()需要没有错误。只要Api.getUser()在调用者内部处理了任何错误,就仍然可以免于处理这些错误。其次,如果Api.getUser()有文件证明不扔,那么期望它不扔是一件非常合理的事情。否则,你必须做出判断,不管它是否可以抛出,以及这些错误是否需要与通过 Promise 传播的错误有任何不同的处理。


推荐阅读