【问题标题】:Async await usage and error handling woes异步等待使用和错误处理问题
【发布时间】:2017-06-08 08:33:09
【问题描述】:

尝试打印Promise { <pending> },第二个打印Unhandled Promise Rejection Warning。我已经成功地将 Promises 与 .then 和 .catch 一起使用,但有些东西我想使用 async/await 以更同步的方式编写代码。我应该改用 Yield 吗?

try {
  var tokens = getNewTokens('refresh-token', 1)
  console.log(tokens)
} catch (error) {
  console.log(error.message)
}

try {
  tokens = getNewTokens('no-such-refresh-token', 1)
  console.log(tokens)
} catch (error) {
  console.log(error.message)
}

function getRefreshToken (refreshToken, userId) {
  return new Promise((resolve, reject) => {
    if (refreshToken === 'refresh-token' && userId === 1) {
      return resolve({
        refreshToken: 'refresh-token',
        accessToken: 'jwt'
      })
    } else {
      const error = Error('Refresh token not found')
      return reject(error)
    }
  })
}

async function getNewTokens (refreshToken, userId) {
  if (!refreshToken || !userId) {
    throw Error('Missing params')
  }
  try {
    var result = await getRefreshToken(refreshToken, userId)
  } catch (error) {
    throw Error(error.message)
  }
  if (!result) {
    throw Error('Something went bonk')
  }
  // Do stuff..
  // get user from DB
  // update refresh token with a new one
  // make new jwt
  return {
    user: {
      id: 1,
      name: 'Jerry',
      role: 'admin'
    },
    newRefreshToken: 'new-refresh-token',
    newAccessToken: 'new-jwt'
  }
}

【问题讨论】:

    标签: javascript node.js async-await


    【解决方案1】:

    使用asyncawait 不会使您的整个程序异步。它使特定功能异步。最后,async 是一种语法糖,可以让编写 Promise 代码更容易。

    async 函数返回Promise。调用异步函数的代码必须将其视为返回承诺的函数。 (唯一的例外是调用async 函数的代码本身在async 函数中,在这种情况下它可以是awaited。)

    因此,抛出 Error 会被转换为 Promise 拒绝。您无法在try..catch 块中捕获它,原因很简单,try..catch 在引发错误之前就结束了! (同样,例外情况是当您从 async 函数调用它时。如果您是 await 异步函数,则 try..catch 块将起作用。在这种情况下,try..catch 块被视为它正在添加一个Promise#catch 函数。)

    您最终必须使用普通的Promise#catch 方法或Promise#then 的第二个参数从async 函数中捕获错误:

    getNewTokens('no-such-refresh-token', 1)
        .then(function(tokens) {
            console.log(tokens);
        }, function(error) {
            console.log(error.message);
        });
    

    【讨论】:

      【解决方案2】:

      async/await 和错误处理初学者的实用答案

      您不能在未使用 async 声明的函数或 promise 之外使用 await 语法。

      async function myAsyncFunction() {
        // code
      }
      

      const myPromiseFunction = () => new Promise((resolve, reject) => {
          // code
      })
      

      所以最终,您必须使用旧的 Promise 方式来使用声明为 async

      的函数
      myAsyncFunction().then(() => console.log('here'));
      

      因为两者都是 Promise。

      现在要像您习惯的那样以 then-catch 方式实际处理错误,您必须像这样构造异步函数...

      async function getUser(username) {
        return await db.users.get({ username });
      }
      

      那么你可以在异步方法之外像普通 Promise 一样使用它......

      getUser()
      .then(user => console.log(user))
      .catch(err => console.error(err));
      

      或者你猜对了,使用 await 在异步函数中使用它。

      async function getJoffery() {
        return await getUser('joffery');
      }
      

      【讨论】:

      • 第一个说法并不完全正确。你仍然可以 await 一个前面没有 async 的函数,只要它返回一个承诺。您也可以在 catch 块内使用throw(err),而不是将Promise 混合到async 函数中;这将是更惯用的方法,因为您试图在这里演示 async/await (在您的示例中,我什至不会使用 catch 块,因为您只是重新抛出错误)。
      • 很酷,我觉得之前的措辞让我感到困惑。这些新示例更清楚您的意图和信息。
      • @CalMlynarczyk 是的,我在异步中也有这种 try-catch 错误的概念。我在本地使用了 RunJS,它故意像你建议的那样抛出,并且“catch”像宣传的那样工作。我确实遇到了这种方法的节点问题,因为它有时会导致未捕获的异常,因此返回 Promise.reject 可以消除这种情况。
      【解决方案3】:

      我想将此作为使用 async/await 处理错误的合理且可读的方式提交。

      const value = await asyncFunction().catch(err => new Error(err))
      if (value instanceof Error) return res.status(500).send('There was an error doing something')
      

      通过添加.catch() 方法,返回一个Error因此将其分配给value变量,我们可以确定我们的变量中会出现一些值。唯一需要的额外代码行是if 语句,用于测试值是否为Error 的实例。如果它因任何原因被捕获,它肯定是一个 instanceof Error(我们的代码确保了这一点),我们的程序可以安全地处理这种情况(在上述情况下,我们返回 500 作为服务器响应,从而阻止程序由于 asyncFunction 中的错误而执行任何危险代码)。

      我有意将其写成两行,以强调可以简洁地编写这一事实,并避免使用许多人不喜欢阅读的 try/catch 块(我自己就是其中之一)。

      如果您对阅读 try/catch 块感到满意,恭喜。我只是发现它使代码看起来很笨拙。那好吧。 ¯\_(ツ)_/¯

      【讨论】:

      • 谢谢。这是否同时处理本地设备上的网络错误(例如,请求可能由于某些扩展而被浏览器阻止)和来自服务器的错误响应?
      • @raisinrising 从上下文来看,这与网络无关。这只是 JavaScript 运行时。如果您的 JS 函数正在进行网络调用,那么这完全取决于该函数的内部是否会将您提到的那些场景视为错误并抛出它们,或者作为特殊的返回值并简单地返回它们。您必须进行试验才能找到答案。
      猜你喜欢
      • 2018-07-29
      • 2017-05-25
      • 2022-01-09
      • 2018-04-06
      • 2016-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-24
      相关资源
      最近更新 更多