admin管理员组文章数量:1391995
I'm using websocket to send and receive data (up to 30 small messages per seconds). I want the client to send a websocket payload and wait for a specific message from the server.
Flow:
The client send a request
It also store the requestId (163) in waitingResponse
object as a new object with sent
timestamp
waitingResponse = {
163: { sent: 1583253453549 }
}
When the server response, another function validate the payload and then append the result to that request object
waitingResponse = {
163: { sent: 1583253453549, action: "none" }
}
The client checks every x ms that object for the action
key
I have a function sendPayload
that sends the payload and then await for a value from awaitResponse
(the function below). Right now this function doesn't work. I tried making 2 separate function, one that would be the setTimeout timer, the other was the promise. I also tried having both in the same function and decide if it was the loop or the promise with the original
argument you can see below. Now I'm thinking that function should always return a promise even in the loop but I cannot seem to make that work with a timer and I'm afraid of the cost of multiple promise in one another. Let's say I check for a response every 5 ms and the timeout it 2000ms. That is a lot of promises.
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] };
}
}
Note: I put the websocket
tag below because I looked hard for that. Maybe I came across the solution without even realising it, but if you have better tags for this question to be found easier, please edit them :)
I'm using websocket to send and receive data (up to 30 small messages per seconds). I want the client to send a websocket payload and wait for a specific message from the server.
Flow:
The client send a request
It also store the requestId (163) in waitingResponse
object as a new object with sent
timestamp
waitingResponse = {
163: { sent: 1583253453549 }
}
When the server response, another function validate the payload and then append the result to that request object
waitingResponse = {
163: { sent: 1583253453549, action: "none" }
}
The client checks every x ms that object for the action
key
I have a function sendPayload
that sends the payload and then await for a value from awaitResponse
(the function below). Right now this function doesn't work. I tried making 2 separate function, one that would be the setTimeout timer, the other was the promise. I also tried having both in the same function and decide if it was the loop or the promise with the original
argument you can see below. Now I'm thinking that function should always return a promise even in the loop but I cannot seem to make that work with a timer and I'm afraid of the cost of multiple promise in one another. Let's say I check for a response every 5 ms and the timeout it 2000ms. That is a lot of promises.
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] };
}
}
Note: I put the websocket
tag below because I looked hard for that. Maybe I came across the solution without even realising it, but if you have better tags for this question to be found easier, please edit them :)
1 Answer
Reset to default 6Yeah, you're mixing a lot of callback style functions with intermediate promises and async
/await
. Don't do polling when waiting for a response! Instead, when writing a queue, put the resolve
function itself in the queue so that you can directly fulfill/reject the respective promise from the response handler.
In your case:
public async sendPayload(details) {
const request = this.waitingResponse[details.requestId] = { sent: +new Date() };
try {
if (this.socket.readyState === WebSocket.OPEN) {
this.socket.send(JSON.stringify(details));
}
const result = await new Promise(function(resolve) {
request.resolve = resolve;
setTimeout(() => {
reject(new Error('Timeout')); // or resolve({action: "to"}), or whatever
}, 5000);
});
console.info("Time took", (+new Date() - request.sent) / 1000);
return result; // or {...request, ...result} if you care
} finally {
delete this.waitingResponse[details.requestId];
}
}
private async processMessage(msg) {
let data = JSON.parse(msg.data);
if (data.hasOwnProperty("requestId") {
const request = this.waitingResponse[data.requestId]
if (request)
request.resolve(data)
else
console.warn("Got data but found no associated request, already timed out?", data)
} else {
console.warn("Got data without request id", data);
}
}
You might even do away with the request
object altogether and only store the resolve
function itself, if the processMessage
function does not need any details about the request.
本文标签: javascriptWebsocket waiting for server response with a queueStack Overflow
版权声明:本文标题:javascript - Websocket waiting for server response with a queue - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744624314a2616225.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论