Uncaught InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state

JavascriptException HandlingWebsocket

Javascript Problem Overview


When my page loads, I try to send a message to the server to initiate a connection, but it's not working. This script block is near the top of my file:

var connection = new WrapperWS();
connection.ident();
// var autoIdent = window.addEventListener('load', connection.ident(), false);

Most of the time, I see the error in the title:

> Uncaught InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state

So I tried to catch the exception, as you can see below, but now it seems InvalidStateError is not defined and that produces a ReferenceError.

Here's the wrapper object for my websocket connection:

// Define WrapperWS




function WrapperWS() {
if ("WebSocket" in window) {
var ws = new WebSocket("ws://server:8000/");
var self = this;



    ws.onopen = function () {
        console.log("Opening a connection...");
        window.identified = false;
    };
    ws.onclose = function (evt) {
        console.log("I'm sorry. Bye!");
    };
    ws.onmessage = function (evt) {
        // handle messages here
    };
    ws.onerror = function (evt) {
        console.log("ERR: " + evt.data);
    };

    this.write = function () {
        if (!window.identified) {
            connection.ident();
            console.debug("Wasn't identified earlier. It is now.");
        }
        ws.send(theText.value);
    };

    this.ident = function () {
        var session = "Test";
        try {
            ws.send(session);
        } catch (error) {
            if (error instanceof InvalidStateError) {
                // possibly still 'CONNECTING'
                if (ws.readyState !== 1) {
                    var waitSend = setInterval(ws.send(session), 1000);
                }
            }
        }
    window.identified = true;
        theText.value = "Hello!";
        say.click();
        theText.disabled = false;
    };

};




}

}

I am testing using Chromium on Ubuntu.

Javascript Solutions


Solution 1 - Javascript

You could send messages via a proxy function that waits for the readyState to be 1.

this.send = function (message, callback) {
    this.waitForConnection(function () {
        ws.send(message);
        if (typeof callback !== 'undefined') {
          callback();
        }
    }, 1000);
};

this.waitForConnection = function (callback, interval) {
    if (ws.readyState === 1) {
        callback();
    } else {
        var that = this;
        // optional: implement backoff for interval here
        setTimeout(function () {
            that.waitForConnection(callback, interval);
        }, interval);
    }
};

Then use this.send in place of ws.send, and put the code that should be run afterwards in a callback:

this.ident = function () {
    var session = "Test";
    this.send(session, function () {
        window.identified = true;
        theText.value = "Hello!";
        say.click();
        theText.disabled = false;
    });
};

For something more streamlined you could look into promises.

Solution 2 - Javascript

This error is raised because you are sending your message before the WebSocket connection is established.

You can solve it by doing this simply:

conn.onopen = () => conn.send("Message");

This onopen function waits for your WebSocket connection to establish before sending your message.

Solution 3 - Javascript

if you use one websocket client object and connect from random app places then object can be in connecting mode (concurent access).

if you want to exchange through only one websoket then create class with promise and keep it in property

class Ws {
  get newClientPromise() {
    return new Promise((resolve, reject) => {
      let wsClient = new WebSocket("ws://demos.kaazing.com/echo");
      console.log(wsClient)
      wsClient.onopen = () => {
        console.log("connected");
        resolve(wsClient);
      };
      wsClient.onerror = error => reject(error);
    })
  }
  get clientPromise() {
    if (!this.promise) {
      this.promise = this.newClientPromise
    }
    return this.promise;
  }
}

create singleton

window.wsSingleton = new Ws()

use clientPromise property in any place of app

window.wsSingleton.clientPromise
  .then( wsClient =>{wsClient.send('data'); console.log('sended')})
  .catch( error => alert(error) )

http://jsfiddle.net/adqu7q58/11/

Solution 4 - Javascript

Method 1: Check connection

You can resolve a promise when socket is connected:

async function send(data) {
    await checkConnection();
    ws.send(data);
}
Implementation

This trick is implemented using an array of resolvers.

let ws = new WebSocket(url);

let connection_resolvers = [];
let checkConnection = () => {
    return new Promise((resolve, reject) => {
        if (ws.readyState === WebSocket.OPEN) {
            resolve();
        }
        else {
            connection_resolvers.push({resolve, reject});
        }
    });
}

ws.addEventListener('open', () => {
    connection_resolvers.forEach(r => r.resolve())
});

Method 2: Wait for connection

You can resolve a promise when socket is not connected:

const MAX_RETRIES = 4;
async function send(data, retries = 0) {
    try {
        ws.send(data);
    } 
    catch (error) {
        if (retries < MAX_RETRIES error.name === "InvalidStateError") {
            await waitForConnection();
            send(data, retries + 1);
        }
        else {
            throw error;
        }
    }
}
Implementation

This trick is implemented using an array of resolvers.

let ws = new WebSocket(url);

let connection_resolvers = [];
let waitForConnection = () => {
    return new Promise((resolve, reject) => {
        connection_resolvers.push({resolve, reject});
    });
}

ws.addEventListener('open', () => {
    connection_resolvers.forEach(r => r.resolve())
});

My opinion is that the second method has a little bit good performance!

Solution 5 - Javascript

It is possible to use functions and readyState with setTimeout.

function openSocket()
{
	webSocket = new WebSocket("");
}
function sendData()
{
	if(webSocket.readyState)
	{
		webSocket.send(JSON.stringify(
		{
			"event"		: "", 
			"message"	: ""
		}));
	}
	else
	{
		setTimeout(sendData, 1000);
	}
}
function eventHandler()
{
    webSocket.onmessage = function(e)
	{
        data  = JSON.parse(e.data);
		event = data.event;

        switch (event)
	    {...}
    }
}

openSocket();
sendData();
enentHandler();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionicedwaterView Question on Stackoverflow
Solution 1 - JavascriptGigablahView Answer on Stackoverflow
Solution 2 - JavascriptManishView Answer on Stackoverflow
Solution 3 - JavascriptRamil GilfanovView Answer on Stackoverflow
Solution 4 - JavascriptAmir FoView Answer on Stackoverflow
Solution 5 - JavascriptRony MacflyView Answer on Stackoverflow