React componentDidMount async/await long polling

Есть сервер, который эмулириует long polling. Нужно слать запросы, пока не придет ответ типа {tickets: [], stop: true}.

Есть код:

 async getTickets(prevToken) {
  const token = prevToken ? prevToken : await this.getToken();
  const response = await fetch(`https://front-test.beta.aviasales.ru/tickets?searchId=${token}`);

  if (response.ok) {
      let tickets = await response.json();
      if (!tickets.stop) {
          await this.getTickets(token);
      } else {
          return tickets.tickets;
          // console.log(tickets.tickets);
      }
  } else if (response.status == '404') {
      await this.getTickets()
  } else {
      await this.getTickets(token);
  }
 }

async componentDidMount() {
  const tickets = await this.getTickets();

  this.setState(state => ({
    tickets: tickets
  }))
}

в стейт возвращает undefined. Если же запускаю так, то возвращается правильный массив:

async getTickets(prevToken) {
  const token = prevToken ? prevToken : await this.getToken();
  const response = await fetch(`https://front-test.beta.aviasales.ru/tickets?searchId=${token}`);

  if (response.ok) {
      let tickets = await response.json();
      ***return tickets.tickets;***
  } else if (response.status == '404') {
      await this.getTickets();
  } else {
      await this.getTickets(token);
  }
}

Каким образом это можно исправить? Примерно понимаю, что проблема возникает из-за растущего стека вызовов, но не хватает знаний, чтобы осилить этот момент.


Ответы (1 шт):

Автор решения: Август

тогда продублирую для Вас ответ, что и в комментарии и отпишу в чём сок ошибки.

return this.getTickets(token) или return await this.getTickets(token).

здесь баг крылся в самом понимании js (в стеках вызовов), но он визуально незаметен, так что я случайно догадался.

когда Ваш первый вызов getTickets проходит неудачно, Вы заново вызываете getTickets. когда Ваш второй вызов getTickets закончился удачно, Вы возвращаете tickets обратно в результат первого getTickets. и получается вот такое:

if (!tickets.stop) {
   await tickets; // результат выполненого второго getTickets, который уже никуда не возвращается (у него нет return)
} else {
   return tickets.tickets;
}

затем стек вызовов заканчивается и Ваш первый getTickets должен закончиться, но он уже ничего не возвращает, так как Вы не указали, что результат tickets нужно вернуть. а так как первый getTickets ничего не возвращает, то по умолчанию его результат будет return undefined, как и у всех функциях, которые явно не указывают return.

→ Ссылка