Привет у меня есть сервер эмулирующей очереди и медленною базу данных на 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 во время чека так как в тот момент контроллер обновился
Как это исправить