等待 Promise.reject 或抛出错误以纾困?

Posted

技术标签:

【中文标题】等待 Promise.reject 或抛出错误以纾困?【英文标题】:await Promise.reject or throw error to bail out? 【发布时间】: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([...]) 另外,它的另一个原因是性能,但在大多数情况下它只是微不足道的。 【参考方案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 对象一起传递,而不是字符串,尽管您可以这样做。

以上是关于等待 Promise.reject 或抛出错误以纾困?的主要内容,如果未能解决你的问题,请参考以下文章

如何在scala play框架中停止执行或抛出错误

Python 2.7.12 Matplotlib x11 转发不显示或抛出多个错误

pthread_attr_setaffinity_np不会返回或抛出错误

Promise.reject的TypeScript错误

程序中凡是可能出现异常的地方必须进行捕获或抛出?对吗?

SonarLint:代码气味:不应声明局部变量,然后立即返回或抛出