I have a WebSocket client that sends a message and receives a response afterwards. I want to be able to call it anywhere and store the response back, like this:
// Global var
var response
// Connection to WS
connect = () => {
return new Promise(function(resolve, reject) {
var server = new WebSocket('ws://localhost:8443/test/');
server.onopen = function() {
resolve(server);
};
server.onerror = function(err) {
console.log(err)
reject(err);
};
});
}
// Send request and receive message back
async request(data){
var request = {
id: "test",
data: data
}
connect().then((server) => {
server.send(JSON.stringify(request))
server.onmessage = ({data}) => {
response = JSON.parse(data) // save result
}
})
.catch(function(err) {
console.log(err)
});
}
// Make request
await request("test")
// Access response
console.log(response) // prints undefined
In the end response is still undefined because when it gets to console.log(response)
the hasn't been updated yet from the asynchronous call.
The only solution that I could come up to was to add a delay like this:
delay(){
var promise = new Promise(function(resolve) {
window.setTimeout(function() {
resolve('done!');
}, 10);
});
return promise;
}
// Make request
await request("test")
// Await for delay
await delay();
// Access response
console.log(response) // prints data received!
Is this the right approach? Seems weird that adding 10ms of delay is enough for it to update. Please let me know if you have a better solution for this than the delay I added.
Your connect()
call is missing await
in front of it. On top of that, you never tell your promise to wait for the response itself. Here's a quick-fix.
await connect().then((server) => {
server.send(JSON.stringify(request))
return new Promise((resolve, reject) => {
server.onmessage = ({data}) => {
response = JSON.parse(data) // save result
resolve()
}
})
})
Technically speaking, you could swap await
for return
since that's your ending statement, and you've placed await
on your request
call.
return connect().then((server) => {
server.send(JSON.stringify(request))
return new Promise((resolve, reject) => {
server.onmessage = ({data}) => {
response = JSON.parse(data) // save result
resolve()
}
})
})
Although it works, I would encourage you to refactor connection init process - there's absolutely no reason to reconnect to WS on every request attempt, unless you're actually disconnecting from it on it's completion.
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await