Повторите попытку async / await, попытайтесь перехватить блок три раза, прежде чем ответить с ошибкой. - PullRequest
0 голосов
/ 18 марта 2019

Нашел похожие проблемы, но ни один из них не ответил на мой вопрос. Мне нужно попытаться запустить асинхронную функцию три раза, прежде чем выдать ошибку. В настоящее время это делается с помощью цикла 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 ]

2 голосов
/ 18 марта 2019

Да, петля 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))
})
2 голосов
/ 18 марта 2019

Вы должны вернуться после res.json({ success: false, message: err && err.message }) следующим образом:

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

1 голос
/ 18 марта 2019

Переместите логику повтора в асинхронную функцию, как показано ниже Это всего лишь пример того, как этого можно достичь, приспособьте его к вашим потребностям.

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("...");
}
...