Как исправить поведение setTimeout для HTTP-запросов? - PullRequest
0 голосов
/ 11 ноября 2019

В моем клиентском приложении я использую Socket IO для проверки непрочитанных событий. Я делаю запрос к своему бэкэнду, который устанавливает тайм-аут 5 секунд, затем переходит к проверке непрочитанных событий и отправляет любые назад.

// client
socket.on("response", ({ mostRecentMessages }) => {
    // do some stuff first
    socket.emit("listenForNew", { userId, currentMessagesFromEveryone });
})
// backend
  socket.on("listenForNew", ({ userId, currentMessagesFromEveryone }) => {
    if (currentMessagesFromEveryone && userId) {
      const { MostRecentMessages } = require("./constants/models");

      const filteredIds = [];

      currentMessagesFromEveryone.forEach(message => {
        filteredIds.push(message.conversation._id);
      });

      console.log("Entered!");

      setTimeout(async () => {
        const mostRecentMessages = await MostRecentMessages.find({
          to: userId,
          date: { $gt: connectedUsersAllMessages[userId].timeIn },
          conversation: { $nin: filteredIds }
        }).populate("to from conversation");

        allMessagesSocket.sockets.connected[
          connectedUsersAllMessages[userId].socketId
        ].emit("response", {
          mostRecentMessages
        });
      }, 5000);
    }
  });

Сначала все работает нормально. Он печатает Entered! один раз для 4, 5 запросов. Затем 6-го числа он начинает печатать Entered! дважды.

Почему это происходит и что я делаю неправильно?

1 Ответ

0 голосов
/ 11 ноября 2019

Я за следующий подход:

  • Ожидание X секунд (в нашем случае - 5)
  • Вызов асинхронной операции (время выполнения неизвестно)
  • Дождаться завершения асинхронного выполнения
  • Дождаться еще X секунд, прежде чем выполнить следующий вызов

Реализация может выглядеть примерно так:

const interval = 5000;

function next() {
  setTimeout(async () => myAsyncOperation(), interval);
}

function myAsyncOperation() {
   const mostRecentMessages = await MostRecentMessages.find({
      to: userId,
      date: { $gt: connectedUsersAllMessages[userId].timeIn },
      conversation: { $nin: filteredIds }
    }).populate("to from conversation");

    allMessagesSocket.sockets.connected[
      connectedUsersAllMessages[userId].socketId
    ].emit("response", () => {
      mostRecentMessages();
      next(); // "next" function call should be invoked only after "mostRecentMessages" execution is completed (or a race condition may be applied)
    }); 
}

next();

Я не скомпилировал этот код, но надеюсь, что концепция ясна

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...