Я использую websocket для отправки и получения данных (до 30 маленьких сообщений в секунду). Я хочу, чтобы клиент отправил полезную нагрузку веб-сокета и дождался определенного сообщения c с сервера.
Поток:
Клиент отправил запрос
Он также хранит requestId (163) в объекте waitingResponse
как новый объект с sent
отметкой времени
waitingResponse = {
163: { sent: 1583253453549 }
}
Когда сервер отвечает, другая функция проверяет полезную нагрузку и затем добавляет результат к этому объекту запроса
waitingResponse = {
163: { sent: 1583253453549, action: "none" }
}
Клиент каждые x мс проверяет этот объект на предмет ключа action
У меня есть функция sendPayload
, которая отправляет полезную нагрузку и затем ожидает значения от awaitResponse
(функция ниже). Сейчас эта функция не работает. Я попытался сделать две отдельные функции, одна из которых была бы таймером setTimeout, другая была обещанием. Я также попытался использовать обе функции в одной и той же функции и решить, был ли это l oop или обещание с аргументом original
, которое вы можете увидеть ниже. Теперь я думаю, что функция всегда должна возвращать обещание даже в l oop, но я не могу заставить это работать с таймером, и я боюсь стоимости многократного обещания друг в друге. Допустим, я проверяю ответ каждые 5 мс и время ожидания составляет 2000 мс. Это много обещаний.
public async sendPayload(details) {
console.log("sendPlayload", details);
this.waitingResponse[details.requestId] = { sent: +new Date() };
if (this.socket.readyState === WebSocket.OPEN) {
this.socket.send(JSON.stringify(details));
}
const bindAwaitResponse = this.awaitResponse.bind(this);
return new Promise(async function (resolve, reject) {
const result = await bindAwaitResponse(details.requestId, true);
console.log("RES", result);
console.info("Time took", (+new Date() - result.sent) / 1000);
resolve(result);
});
}
public async awaitResponse(requestId, original) {
// console.log(requestId, "awaitResponse")
return new Promise((resolve, reject) => {
// Is it a valid queued request
if (this.waitingResponse[requestId]) {
// Do we have an answer?
if (this.waitingResponse[requestId].hasOwnProperty("action")) {
console.log(requestId, "Got a response");
const tmp = this.waitingResponse[requestId];
delete this.waitingResponse[requestId]; // Cleanup
resolve(tmp);
} else {
// No answer yet from remote server
// console.log("no answer: ", JSON.stringify(this.waitingResponse));
// Check if request took too long
if (+new Date() - this.waitingResponse[requestId].sent > 5000) { // TODO: Option for time out
console.warn(requestId, "Request timed out");
// Timed out, result took too long
// TODO: Option, default action when timed out
delete this.waitingResponse[requestId]; // Cleanup
resolve({
action: "to" // For now, just sent a timeout action, maybe the default action should be outside of the Network class?
})
} else {
// console.log(requestId, "Still waiting for results");
console.log(JSON.stringify(this.waitingResponse));
// Still waiting, after x ms, recall function
return setTimeout(async () => { resolve(await this.awaitResponse(requestId, false)); }, 200);
}
}
}
});
}
private async processMessage(msg) {
console.log("WS received Message", JSON.stringify(msg.data));
console.log("Current: ", JSON.stringify(this.waitingResponse));
let data = JSON.parse(msg.data);
// console.log("Received: ", data);
if (data.hasOwnProperty("requestId") && this.waitingResponse[data.requestId]) {
// console.log("processMessage ID found");
this.waitingResponse[data.requestId] = { ...data, ...this.waitingResponse[data.requestId] };
}
}
Примечание: я поставил тег websocket
ниже, потому что я искал это усердно. Возможно, я натолкнулся на решение, даже не осознавая его, но если у вас есть лучшие теги для этого вопроса, которые можно найти проще, отредактируйте их:)