@hinie

Как обновить запрос используя AbortController?

Привет у меня есть сервер эмулирующей очереди и медленною базу данных на nodeJs:22
const http = require("http");
const url = require("url");

let messages = [];
let queue = [];

const processQueue = () => {
  if (queue.length > 0) {
    //long operation of doing something
    setTimeout(() => {
      const [message, res] = queue.shift();
      messages.push(message);
      console.log(messages);
      res.end();
      processQueue();
    }, 3000);
  } else {
    // infinite loop of queue being processed
    setTimeout(() => {
      processQueue();
    }, 10);
  }
};
//queue worker always runs, checks queue etc...
processQueue();

const server = http.createServer((req, res) => {
  const parsedUrl = url.parse(req.url, true);
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Methods", "OPTIONS, GET, POST");
  res.setHeader("Access-Control-Allow-Headers", "*");

  if (parsedUrl.pathname === "/messages") {
    if (req.method === "GET") {
      res.setHeader("Content-Type", "application/json");
      res.end(JSON.stringify(messages));
    }
    if (req.method === "OPTIONS") {
      res.end();
    }
    if (req.method === "POST") {
      let body = "";
      req.on("data", (chunk) => {
        body += chunk.toString();
      });
      req.on("end", () => {
        const message = JSON.parse(body);
        queue.push([message, res]);
        //res here is used just a way to close request only when operation has been processed
      });
    }
  }
});

server.listen(3000, () => {
  console.log("Server listening on port 3000");
});

Код сервера менять нельзя:)
А тут код клиента без AbortController
<button id="add" onclick="addMessage(generateMessage())">addmessage</button>
<div id="container"></div>
<script>
  function generateMessage() {
    return {
      text: (Math.random() + 1).toString(36).substring(7)
    };
  }
  async function updateMessages() {
    let response = await fetch("http://localhost:3000/messages");
    let messages = await response.json();
    counter = messages.length;
    let container = document.getElementById("container");
    container.innerHTML = "";
    renderMessages(messages);
  }
  function renderMessages(messages) {
    messages.forEach((message) => {
        addMessageDom(message)
    });
  }
  function addMessageDom(message){
    let messageWrapper = document.createElement("div");
    messageWrapper.innerText = message.text;

    let container = document.getElementById("container");
    container.appendChild(messageWrapper);
  }
  async function addMessage(message) {
    addMessageDom(message)
    let response = await fetch("http://localhost:3000/messages", {
      method: "POST",
      body: JSON.stringify(message),
      headers: {
        'Content-Type': 'application/json'
      }
    }).then(() => {
      updateMessages();
    });
  }
  updateMessages();
</script>


Если я запущу сервер и открою index.html, я увижу текущие сообщения и кнопку для отправки сообщения. Получение сообщений на сервере работает мгновенно, но Post занимает 3 секунды и выполняется в очереди.

Чтобы оптимизировать сообщение и сделать его видимым сразу после отправки, оно отображает добавленное сообщение и только после успешного выполнения запроса post обновляет сообщения.

Проблема в том, что если я быстро нажму addmessage 2, 3 или более раз, показанные сообщения будут мигать, чтобы избежать этого поведения, я хотел бы отменить все предыдущие запросы на получение сообщений в функции updateMessages, это означает, что сообщения не будут мигать и всегда будут актуальными :)

Я попытался добавить AbortController таким образом для функции updateMessages.
let controller = new AbortController();
  async function updateMessages() {
    controller.abort();
    controller = new AbortController();
    let response = await fetch("http://localhost:3000/messages", {signal: controller.signal});
    let messages = await response.json();
    counter = messages.length;
    let container = document.getElementById("container");
    container.innerHTML = "";
    renderMessages(messages);
  }

Но єто не помогло, думаю потому что controller обновился, а чек оборван ли сигнал происходит асинхронно то-есть aborted будет false во время чека так как в тот момент контроллер обновился
Как это исправить
  • Вопрос задан
  • 96 просмотров
Пригласить эксперта
Ответы на вопрос 1
VK_31
@VK_31
Постоянно учусь
Сообщения мигают из-за
container.innerHTML = "";.

Попробуйте обернуть в try catch
controller.abort();
controller = new AbortController();
try{
    let response = await fetch("http://localhost:3000/messages", {signal: controller.signal});
    let messages = await response.json();
    counter = messages.length;
    let container = document.getElementById("container");
    container.innerHTML = "";
    renderMessages(messages);
} catch (e) {
  console.error(e);
}
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы