Почему Await не блокирует следующую строку кода?

#javascript #promise #async-await #axios

#javascript #обещание #async-await #axios

Вопрос:

Я использую асинхронную функцию для запуска сервера, проверки возврата URL-адреса 200 , а затем запускаю свои тесты, но моя checkUrl функция не завершается до запуска следующей строки кода.

Я использую axios пакет для проверки URL-адреса для получения кода состояния, и я пробовал несколько вариантов async / await и Promise.resolve() .

 function checkUrl(url) {
  console.log(`Checking for ${url}`);

  return axios
    .get(url)
    .then(function(res) {
      const message = `${url} is status code: ${res.status}`;

      return res;
    })
    .catch(function(err) {
      console.log("Will check again in 5 seconds");
      setTimeout(() => {
        return checkUrl(url);
      }, 5000);
    });
}

async function init() {
  let val;

  console.log("Running tests:::");
  // start server in react-integration directory
  shell.exec("BROWSER=none yarn start", {
    cwd: "sampleIntegration/react-integration",
    async: true
  });
  // check server has started
  val = await checkUrl("http://localhost:3000");

  console.log(`value from checkUrl promise: ${val}`);
}
  

Я ожидаю, что переменной val будет сообщение, возвращаемое из Promise.resolve() моей checkUrl функции.

val возвращается неопределенным.

Комментарии:

1. Значение возвращается undefined в обоих случаях или только для случая ошибки?

2. shell.exec является асинхронным, поэтому при вызове checkurl сервер может быть еще недоступен, что приводит axios.get к переходу в ветку catch. Оттуда вы ничего не возвращаете, таким образом, конечный результат не определен

3. консоль. журнал запускается только один раз после регистрации блока catch. Checking for http://localhost:3000 Will check again in 5 seconds value from checkUrl promise: undefined Как только обещание выполняется, я получаю, http://localhost:3000 is status code: 200 но строка под функцией уже запущена.

4. И я также не уверен, разрешает ли axios или отклоняет, когда код состояния http равен != 2xx

5. return Внутри setTimeout не выполняет то, что вы, вероятно, думаете, что это делает. Этот блок совершенно не связан с результатом блока catch. Фактически, ваш блок catch пока не дает никакого результата val == undefined .

Ответ №1:

Проблема в том, setTimeout что в блоке catch. Это асинхронно, но блок catch немедленно возвращается. Поскольку ему нечего возвращать, он возвращает undefined. Чтобы решить эту проблему (а также сохранить желаемое поведение ожидания), вы могли бы сделать что-то вроде этого:

 function checkUrl(url) {
  console.log(`Checking for ${url}`);

  return axios.get(url)
    .then(res => {
      const message = `${url} is status code: ${res.status}`;
      return res;
    })
    .catch(err => {
      console.log('Will check again in 5 seconds');
      return new Promise((resolve) => {
         setTimeout(resolve, 5000);
      }).then(() => checkUrl(url));
    });
}
  

Это создаст обещание, которое разрешается через 5 секунд, и при разрешении оно вызывает checkUrl .

Комментарии:

1. Отличная работа @derpirscher. Я не видел вашего ответа, но, похоже, мы находимся на одной странице. Спасибо за вашу помощь!