I am working with a WebSocket and trying to be able to send socket data at anytime from throughout my application. When I attempt to access the send command from within another function, I am receiving:
Uncaught InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable.
This only is occuring when I call a function, this is how I am setting up my websocket:
Main.socket = (function() {
var socket = new WebSocket("ws://server:port");
socket.onopen = function() {
console.log("Socket has been opened!");
}
function send() {
socket.send('test');
}
return {
socket: socket,
send: send
}
})();
I am able to call the function globally, and also when I console.log Main.socket from within a function it is able to see the socket. But when I call the send function I get that error.
Here is an alternative solution to waiting for the web socket connection to come online, replace your call to :
function send() {
web_socket.send('test');
}
with this :
function send(msg) {
wait_for_socket_connection(socket, function() {
socket.send(msg);
});
};
function wait_for_socket_connection(socket, callback){
setTimeout(
function(){
if (socket.readyState === 1) {
if(callback !== undefined){
callback();
}
return;
} else {
console.log("... waiting for web socket connection to come online");
wait_for_socket_connection(socket,callback);
}
}, 5);
};
The problem is that the socket has not been opened yet. WebSocket.send
cannot be used until the asynchronous onopen
event occurs.
While using setTimeout
(for a long enough duration) "should work", the correct way to deal with asynchronous JavaScript programming is to treat program flow as a sequence of dependent events.
In any case, here is a small example showing how to use a jQuery Deferred Object which (as of jQuery 1.8 isn't broken and honors the Promises/A contract):
Main.socket = (function($) {
var socket = new WebSocket("ws://server:port");
// Promise will be called with one argument, the "send" function for this
// socket.
var readyPromise = $.Deferred();
socket.onopen = function() {
console.log("Socket has been opened!");
readyPromise.resolve(socket.send)
}
return readyPromise;
})(jQuery);
Then later, in the code that uses this little module:
Main.socket.then(function (send) {
// This will only be called after `Promise.resolve` is called in the module
// which will be called in the `WebSocket.onopen` callback.
send("Hello world!");
})
// This code may or may not execute before the `then` function above
// depending upon the state the Promise/Deferred Object.
// However, we can get consistent program flow by using `then`-chaining
// of promises.
Of course you don't have to use Promises - callbacks will work just fine, although I prefer the unified contract/framework of Promises - and you can use whatever names or structure is most fitting.
Also, note that it might not be good to have a single WebSocket for the entire page lifecycle as this won't correctly handle disconnect and recovery scenarios.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With