繁体   English   中英

在响应错误之前重试 async/await try 和 catch 块 3 次

[英]Retry async/await try and catch block three times before responding with an error

发现了类似的问题,但都没有回答我的问题。 在抛出错误之前,我需要尝试运行异步函数三次。 目前用 while 循环来做,一开始就感觉不对。 这一切都发生在一条快速路线上。 这是我的代码目前的样子:

const MAX_NUMBER_OF_TRIES = 3
router.post('/', async function (req, res) {
  let tries = 0
  while (true) {
    try {
      await myAsyncFunction(body)
      res.json({ success: true, message: 'Done!' })
    } catch (err) {
      if (tries >= MAX_NUMBER_OF_TRIES) {
        res.json({ success: false, message: err && err.message })
      }
    }
    tries++
  }
}

问题之一是,当我这样做时,我总是收到以下错误:

UnhandledPromiseRejectionWarning: 错误 [ERR_HTTP_HEADERS_SENT]: 发送到客户端后无法设置标头

没有循环就不会出现这种情况。 所以我想问题是,如何在响应错误之前将这些调用限制为 3 次尝试? 这是正确的路径还是有其他方法可以做到? 为什么我会遇到标题问题?

你应该在res.json({ success: false, message: err && err.message })像这样返回:

...
res.json({ success: false, message: err && err.message })
return
...

是的, while循环看起来很粗略。 你永远不会阻止它。 只需使用普通循环即可。 当你得到回应时,你也需要休息。

const MAX_NUMBER_OF_TRIES = 3
router.post('/', async function (req, res) {
  var message;
  for (let tries = 0; tries < MAX_NUMBER_OF_TRIES; tries++) {
    try {
      await myAsyncFunction(body)
      res.json({ success: true, message: 'Done!' })
      return
//    ^^^^^^
    } catch (err) {
      message = err && err.message;
      console.log(`Try ${tries}: ${err}`)
    }
  }
  res.json({ success: false, message })
}

这种奇怪的小控制流的替代方法是使用递归,它非常适合重试:

async function getResult(body, retries) {
  try {
    await myAsyncFunction(body)
    return {success: true, message: 'Done'}
  } catch(err) {
    if (retries > 0)
      return getResult(body, retries-1)
    else
      return {success: false, message: err && err.message}
  }
}

const MAX_NUMBER_OF_TRIES = 3
router.post('/', async function (req, res) {
  const RETRIES = MAX_NUMBER_OF_TRIES - 1
  res.json(await getResult(body, RETRIES))
})

将重试逻辑移动到 async 函数,如下所示这只是一个如何实现的示例,请根据您的需要进行调整。

router.post('/', async function(req, res) {
  try {
    var result = await asyncFunc(3 /* retries */);
    res.send(result);
  } catch(ex)
  {
    res.send(ex);
  }
})

在你的异步函数中,你可以实现类似的东西

async asyncFunc(retries)
{
  for(var i = 0; i < retries; i++)
  {
    var result = await doSomething();
    if(result)
    {
      // break the loop
      return result;
    }
  }

   // if we land here, so the number of retries was exceeded
   throw Error("...");
}

async-retry包会为你做这件事; 代码量实际上最终是相似的,但它的功能要多一些,而且要正确使用也不那么繁琐。

例如:

const retry = require('async-retry')

try {
  await retry(async () => {
    await myAsyncFunction(body)
    res.json({ success: true, message: 'Done!' })
  }, {
    retries: 3,
  }) 
} catch (err) => 
{
   res.json({ success: false, message: err && err.message })
}

外部 catch 处理它重试 3 次并逃脱retry块的情况。 您还可以设置一个onError函数,该函数具有要为每个错误(例如日志记录)执行的逻辑。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM