【问题标题】:await Promise.reject or throw error to bail out?等待 Promise.reject 或抛出错误以纾困?
【发布时间】:2018-11-07 14:13:54
【问题描述】:

我正在将我的承诺链代码重构为异步/等待风格。这样做的原因之一是我想要一个单独的 catch 块来处理所有错误情况(如此处所述Understanding promise rejection in node.js

我的问题是,当我遇到同步错误时,我应该致电await Promise.rejectthrow error 来解决这个过程吗? 我知道任何一种方式都可以,但我更喜欢throw error。我已经知道我得到了无效的结果,为什么还要等待?使用 throw 立即终止控制流似乎是一个更好的选择。

我不是在谈论承诺链(我的问题的重点),所以我不认为线程 JavaScript Promises - reject vs. throw 回答了我的问题。

我阅读了Error Handling in Node.js 的文章,我认为它也没有给出答案。但它确实说

一个给定的函数应该会产生操作错误 同步(使用 throw)或异步(使用回调或事件) 发射器),但不是两者都。 ... 一般来说,使用 throw 和 Expecting 使用 try/catch 的调用者非常少见……

我的异步函数可能会返回 Promise.reject。因此,我担心引入 2 种方法来传递该文章所针对的错误。

try {
   let result = await aysncFunc().
   if (!isResultValid(result)) { //isResultValid() is sync function 
      await Promise.reject('invalid result')
      //or throw 'invalid result'
   }
   ... //further processing
}
catch (error) {
  ...
}

【问题讨论】:

  • I know either way will work but I prefer throw error - 好吧,继续做吧 - 但你确定任何一种方法都行吗?
  • "但是你确定任何一种方法都行吗?"我有 99% 的把握。但这也是我提出问题的原因之一。
  • 当然它是 100% 有效的(就像在你的代码块中一样)。我更喜欢直接抛出错误+1,你在同步代码中抛出的任何东西都可能被捕获。它只是更加优雅和自然。 await Promise.reject() 是多余的,可能会引起某些人的困惑。
  • 但我认为你可能会走向错误的方向。不要为了时髦而使用async/await。在真正需要的时候使用它;即异步操作,如果您有两个或更多独立的异步操作,也可以使用await Promise.all([...])
  • 另外,它的另一个原因是性能,但在大多数情况下它只是微不足道的。

标签: javascript node.js promise async-await


【解决方案1】:

在 Promise 控制流中使用 throw 在语义上是正确的,这通常是摆脱 Promise 链的首选方式。

根据编码风格,await Promise.reject(...) 可用于区分实际错误和预期拒绝。带有字符串原因的拒绝承诺是有效的,但 throw 'invalid result' 被认为是样式问题,可以使用 linter rules 解决,因为通常使用 Error 实例作为例外。

之所以重要,是因为使用instanceof Error 无法检测到字符串异常并且没有message 属性,将错误记录为console.warn(error.message) 将导致undefined 条目模糊不清。

// ok
class Success extends Error {}
try {
  throw new Success('just a friendly notification');
} catch (err) {
  if (!(err instanceof Success)) {
    console.warn(err.message);
    throw err;
  }
}

// more or less
const SUCCESS = 'just a friendly notification';
try {
  await Promise.reject(SUCCESS);
} catch (err) {
  if (err !== SUCCESS)) {
    console.warn(err.message);
    throw err;
  }
}

// not ok
try {
  throw 'exception';
} catch (err) {
  if (typeof err === 'string') {
    console.warn(err);
  } else {
    console.warn(err.message);
  }

  throw err;
}

由于invalid result实际上是一个错误,所以它是合理的:

  throw new TypeError('invalid result');

我不是在谈论承诺链(我的问题的全部意义),所以我不认为线程 JavaScript Promises - reject vs. throw 回答了我的问题。

async函数是promise链的语法糖,所以所有适用于promise的点也适用于async

在某些情况下,抛出错误与拒绝 Promise 不同,但它们特定于其他 Promise 实现,例如 AngularJS $q,并且不会影响 ES6 Promise。 Promise构造函数中的同步错误导致异常,这也不适用于async

【讨论】:

  • 我添加了“我不是在谈论承诺链......”只是为了强调我知道那个讨论(以防有人会说这是一个重复的问题)。另外,我更关心使用其中一种的利弊
  • 风格问题,throw 更传统。我希望我涵盖了优点和缺点。 在 promise 控制流中使用 throw 在语义上是正确的 vs Rejected promise with string reason is valid but throw 'invalid result'被认为是样式问题
  • 顺便说一句,Node.js 中的错误处理文章确实说过“给定的函数应该同步(使用 throw)或异步(使用回调或事件发射器)传递操作错误,但不能同时传递。”
  • 由于async 引入了类似同步的控制流,因此适用的是句子的第一部分。
  • 真的有人throw 是一个普通字符串吗...?!来吧,这真是一个糟糕的做法。正如我所说,对于利弊,IMO,如果你知道你有 sync 操作,那么使用 await Promise.reject() 根本没有任何优点。它就像你有一个函数,并用另一个函数包装,它只返回函数。 PS。 Promise.reject() 也应该与 error 对象一起传递,而不是字符串,尽管您可以这样做。
猜你喜欢
  • 1970-01-01
  • 2018-12-20
  • 1970-01-01
  • 1970-01-01
  • 2018-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多