Invalid state Error on websockets when sending message - javascript

I'm working on app which send message via websockets (managed by django channels) and in return it receives json from django db as a message and renders frontend based on that json.
I have Invalid State Error when I try to send message by websocket, why? Messages send are usually Json. I works properly all the time but commented part doesn't and I don't know why please explain me.
function main() {
configGame();
}
function configGame() {
const socket = "ws://" + window.location.host + window.location.pathname;
const websocket = new WebSocket(socket);
const playerName = document.querySelector(".playerName_header").textContent;
function asignEvents() {
const ready_btn = document.querySelector(".--ready_btn");
const start_btn = document.querySelector(".--start_btn");
ready_btn.addEventListener("click", () => {
let mess = JSON.stringify({
player: playerName,
action: "ready",
});
sendMess(mess);
});
start_btn.addEventListener("click", () => {
let mess = JSON.stringify({
player: playerName,
action: "start",
});
sendMess(mess);
});
}
function openWebsocket() {
console.log("Establishing Websocket Connection...");
websocket.onopen = () => {
console.log("Websocket Connection Established!");
};
}
function setWebsocket() {
websocket.onmessage = (mess) => {
console.log(`Message: ${mess.data}`);
dataJson = JSON.parse(mess.data);
dataJson = JSON.parse(dataJson.message);
//Player Ready (jeszcze z max_players zrobic kontrolke)
if (dataJson.action === "player_ready") {
const playersReadyText = document.querySelector(".players_ready_text");
playersReadyText.textContent = `Players ready: ${dataJson.players_ready}`;
}
};
websocket.onclose = () => {
console.log("Websocket Connection Terminated!");
};
}
/*
function checkState() {
let mess = JSON.stringify({
player: playerName,
action: "game state",
});
sendMess(mess);
}
*/
function sendMess(messText) {
websocket.send(messText);
}
openWebsocket();
checkState(); //This one doesn't work
asignEvents();
setWebsocket();
}
// Asigning Event Listneres to DOM ELEMENTS
function asignEvents() {
const ready_btn = document.querySelector(".--ready_btn");
const start_btn = document.querySelector(".--start_btn");
ready_btn.addEventListener("click", () => {
console.log("Ready");
});
start_btn.addEventListener("click", () => {
console.log("Start");
});
}
main();
Error:
Console (Safari) returns InvalidState error and points to
method checkState and sendMess.
InvalidStateError: The object is in an invalid state.

Is the websocket connected?
sendMess(messText) {
if (websocket.readyState === WebSocket.OPEN) {
websocket.send(messText);
} else {
console.warn("websocket is not connected");
}
}

Related

Loop with socket function doesn't work - WebSocket

I have a socket endpoint, that I connect to and send a message to get a user.
I used this code to do it :
import generateConnection from './generate-connection';
export async function fetchUser(id: number) {
return new Promise(function (resolve) {
const connection = generateConnection();
connection.onopen = () => {
connection.send(
JSON.stringify(
'{"msg":"connect","version":"1","support":["1","pre2","pre1"]}',
),
);
connection.send(
JSON.stringify(
`{"msg":"method","id":"1","method":"Users.getUser","params":[${id}]}`,
),
);
console.log('Connected');
};
connection.on('message', async (event) => {
const data = event.toString();
if (data[0] == 'a') {
const a = JSON.parse(JSON.parse(data.substring(1))[0]);
if (a.msg == 'result') {
if ('error' in a) {
console.log('Error' + a.error.msg);
return null;
} else {
resolve(a.result);
}
}
}
});
connection.on('error', function (error) {
console.log('Connection Error: ' + error.toString());
});
connection.on('close', function () {
console.log('echo-protocol Connection Closed');
});
});
}
const fetchAllUsers = async () => {
for (let i = 0; i < 100; i++) {
const user: any = await fetchUser(i);
console.log(user.name);
}
};
fetchAllUsers();
I get the following result :
Connected
Jack
It just give me the first user and it stop on the second.
I have no control over the socket and I want to be able to fetch all 5000 users each day to be synced.
I'm Using WebSocket for this problem.
If you have any proposition other than this method, I'm all ears :D
To explain more :
1 - I want to open a connection
2 - Send a message
3 - get Result
4 - Add to Array or db
5 - When finished, close the connection.
6 - repeat
Why would you close the connection every time? An open connection allows you to send many messages. But maybe it is easier to:
connection.close()
// right before:
resolve(a.result);
If that didn't work maybe it's time to send more then one request per connection. Try this (I'm a little rusty with promises so I hope you get the idea and improve it)
import generateConnection from './generate-connection';
export async function fetchAllUsers() {
var total = 100;
var returned = 0;
var all_results = [];
return new Promise(function(resolve) {
const connection = generateConnection();
connection.onopen = () => {
connection.send(
JSON.stringify(
'{"msg":"connect","version":"1","support":["1","pre2","pre1"]}',
),
);
for (var i = 0; i < total; i++) {
connection.send(
JSON.stringify(
`{"msg":"method","id":"1","method":"Users.getUser","params":[${i}]}`,
),
);
}
console.log('Connected');
};
connection.on('message', async(event) => {
const data = event.toString();
if (data[0] == 'a') {
const a = JSON.parse(JSON.parse(data.substring(1))[0]);
if (a.msg == 'result') {
if ('error' in a) {
console.log('Error' + a.error.msg);
return null;
} else {
console.log(a.result.name);
all_results.push(a.result);
returned++;
if (returned == total) {
resolve(all_results);
}
}
}
}
});
connection.on('error', function(error) {
console.log('Connection Error: ' + error.toString());
});
connection.on('close', function() {
console.log('echo-protocol Connection Closed');
});
});
}
fetchAllUsers();

how to do websocket connection event inside of express`s get request?

im trying to get websocket in express`s router.get request
here the code
app.js
const { createServer } = require("http");
const mongoose = require('mongoose');
const config = require('./config');
const WebSocket = require('ws');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
const server = createServer(app);
app.use("/RegisterApi", require("./Routes/RegisterApi/RegisterApi"));
const wss = new WebSocket.Server({ server });
app.wss = wss;
app.locals.clients = [];
server.listen(config.PORT, function () {
console.log(`im listening at ${config.PORT}`);
mongoose.connect(config.MONGODB_URI, {
useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true,
useFindAndModify: false
})
RegisterApi.js
const router = express.Router();
const nodemailer = require("nodemailer");
const Users = require("../../Models/YakutGamesUserModel");
const WebSocket = require('ws');
//const jwt = require("jsonwebtoken");
router.get('/login'/*,verifyToken*/, async (req, res) => {
console.log(req.query.name);
const currentUser = await Users.findOne({ name: req.query.name });
const userunchecked = false;
if (!currentUser) {
res.send("invalid user ");
userunchecked = true;
}
else if (!currentUser.confirmed) {
res.send("confirm your email " + currentUser.name); userunchecked = true;
}
else if (currentUser.password !== req.query.password) { res.send("password is wrong"); userunchecked = true; }
const wss = req.app.wss;
const clients = req.app.locals.clients;
await wss.once("connection", (ws, request) => {
console.log("Total connected clients:", wss.clients.size);
const ip = request.connection.remoteAddress;
console.log(ip);
if (userunchecked) { ws.delete; console.log('wtf'); return; }
const userObject = { id: currentUser._id, object: ws };
clients.push(userObject);
ws.send("ID= " + currentUser._id);
});
});
those are server side
as a client im using unity
unity code C#
async void Login()
{
newUser.name = namefield.text;
newUser.password = passfield.text;
string url = String.Format("http://localhost:7989/RegisterApi/login?name={0}&password={1}", newUser.name, newUser.password);
StartCoroutine(LoginUser(url, () => { Debug.Log("login req done"); }));
websocket = new WebSocket("ws://localhost:7989/RegisterApi/login");
websocket.OnOpen += () =>
{
Debug.Log("Connection open!");
};
websocket.OnError += (e) =>
{
Debug.Log("Error! " + e);
};
websocket.OnClose += (e) =>
{
Debug.Log("Connection closed!");
};
websocket.OnMessage += (bytes) =>
{
var message = System.Text.Encoding.UTF8.GetString(bytes);
Debug.Log("OnMessage! " + message);
};
await websocket.Connect();
}
problem is server do not get console.log("Total connected clients:", wss.clients.size); at first time when i fire login function from unity. but if i fire login second time server get that but this time wss.clients.size will be 2 .
what am i doing wrong?
I think you are trying to log in ,with http request you can do once.
This code worked for me.
IEnumerator LoginUser(string url, Action onSuccess)
{
UnityWebRequest req = UnityWebRequest.Get(url);
yield return req.SendWebRequest();
while (!req.isDone)
yield return null;
string result = req.downloadHandler.text;
string[] resultArray = result.Split(' ');
if (resultArray[0] == "yourCode")
{
myTempID = resultArray[1];
Debug.Log(myTempID);
Wss(myTempID);
LoginLog.GetComponent<TextMeshProUGUI>().text = "login done";
mainMenuButtonHandlersGO.GetComponent<MainMenuButtonHandlers>().OpenFirstCanvasButtons();
messageHandlerGO.GetComponent<WssMessageHandler>().MessageHandlerFunction();
}
else LoginLog.GetComponent<TextMeshProUGUI>().text = result;
onSuccess();
}
async void Wss(string code)
{
websocket = new WebSocket(String.Format("ws://{1}:7989/RegisterApi/login?parentID={0}", code, mainAddress));
websocket.OnOpen += () =>
{
Debug.Log("Connection open!");
};
websocket.OnError += (e) =>
{
Debug.Log("Error! " + e);
};
websocket.OnClose += (e) =>
{
Debug.Log("Connection closed!");
};
// Keep sending messages at every 0.3s
//InvokeRepeating("SendWebSocketMessage", 0.0f, 5.0f);
// waiting for messages
await websocket.Connect();
}

Always throws registration failed error while subscribing push notifications

I am working on solutions using which i can send desktop push notification to subscribed clients.
I have created basic solution in where whenever user click on button i ask user for whether they want to allow notifications for my app or not!
I am getting an error of "Registration failed - permission denied" whenever i click on button for first time.
So that i am not able to get required endpoints to save at backend
Here is my code
index.html
<html>
<head>
<title>PUSH NOT</title>
<script src="index.js"></script>
</head>
<body>
<button onclick="main()">Ask Permission</button>
</body>
</html>
index.js
const check = () => {
if (!("serviceWorker" in navigator)) {
throw new Error("No Service Worker support!");
} else {
console.log("service worker supported")
}
if (!("PushManager" in window)) {
throw new Error("No Push API Support!");
} else {
console.log("PushManager worker supported")
}
};
const registerServiceWorker = async () => {
const swRegistration = await navigator.serviceWorker.register("/service.js?"+Math.random());
return swRegistration;
};
const requestNotificationPermission = async () => {
const permission = await window.Notification.requestPermission();
// value of permission can be 'granted', 'default', 'denied'
// granted: user has accepted the request
// default: user has dismissed the notification permission popup by clicking on x
// denied: user has denied the request.
if (permission !== "granted") {
throw new Error("Permission not granted for Notification");
}
};
const main = async () => {
check();
const swRegistration = await registerServiceWorker();
const permission = await requestNotificationPermission();
};
// main(); we will not call main in the beginning.
service.js
// urlB64ToUint8Array is a magic function that will encode the base64 public key
// to Array buffer which is needed by the subscription option
const urlB64ToUint8Array = base64String => {
const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, "+")
.replace(/_/g, "/");
const rawData = atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
};
const saveSubscription = async subscription => {
console.log("Save Sub")
const SERVER_URL = "http://localhost:4000/save-subscription";
const response = await fetch(SERVER_URL, {
method: "post",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(subscription)
});
return response.json();
};
self.addEventListener("activate", async () => {
try {
const applicationServerKey = urlB64ToUint8Array(
"BFPtpIVOcn2y25il322-bHQIqXXm-OACBtFLdo0EnzGfs-jIGXgAzjY6vNapPb4MM1Z1WuTBUo0wcIpQznLhVGM"
);
const options = { applicationServerKey, userVisibleOnly: true };
const subscription = await self.registration.pushManager.subscribe(options);
console.log(JSON.stringify(subscription))
const response = await saveSubscription(subscription);
} catch (err) {
console.log(err.code)
console.log(err.message)
console.log(err.name)
console.log('Error', err)
}
});
self.addEventListener("push", function(event) {
if (event.data) {
console.log("Push event!! ", event.data.text());
} else {
console.log("Push event but no data");
}
});
Also i have created a bit of backend as well
const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const webpush = require('web-push')
const app = express();
app.use(cors());
app.use(bodyParser.json());
const port = 4000;
app.get("/", (req, res) => res.send("Hello World!"));
const dummyDb = { subscription: null }; //dummy in memory store
const saveToDatabase = async subscription => {
// Since this is a demo app, I am going to save this in a dummy in memory store. Do not do this in your apps.
// Here you should be writing your db logic to save it.
dummyDb.subscription = subscription;
};
// The new /save-subscription endpoint
app.post("/save-subscription", async (req, res) => {
const subscription = req.body;
await saveToDatabase(subscription); //Method to save the subscription to Database
res.json({ message: "success" });
});
const vapidKeys = {
publicKey:
'BFPtpIVOcn2y25il322-bHQIqXXm-OACBtFLdo0EnzGfs-jIGXgAzjY6vNapPb4MM1Z1WuTBUo0wcIpQznLhVGM',
privateKey: 'mHSKS-uwqAiaiOgt4NMbzYUb7bseXydmKObi4v4bN6U',
}
webpush.setVapidDetails(
'mailto:janakprajapati90#email.com',
vapidKeys.publicKey,
vapidKeys.privateKey
)
const sendNotification = (subscription, dataToSend='') => {
webpush.sendNotification(subscription, dataToSend)
}
app.get('/send-notification', (req, res) => {
const subscription = {endpoint:"https://fcm.googleapis.com/fcm/send/dLjyDYvI8yo:APA91bErM4sn_wRIW6xCievhRZeJcIxTiH4r_oa58JG9PHUaHwX7hQlhMqp32xEKUrMFJpBTi14DeOlECrTsYduvHTTnb8lHVUv3DkS1FOT41hMK6zwMvlRvgWU_QDDS_GBYIMRbzjhg",expirationTime:null,keys:{"p256dh":"BE6kUQ4WTx6v8H-wtChgKAxh3hTiZhpfi4DqACBgNRoJHt44XymOWFkQTvRPnS_S9kmcOoDSgOVD4Wo8qDQzsS0",auth:"CfO4rOsisyA6axdxeFgI_g"}} //get subscription from your databse here.
const message = 'Hello World'
sendNotification(subscription, message)
res.json({ message: 'message sent' })
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
Please help me
Try the following code:
index.js
const check = () => {
if (!("serviceWorker" in navigator)) {
throw new Error("No Service Worker support!");
} else {
console.log("service worker supported")
}
if (!("PushManager" in window)) {
throw new Error("No Push API Support!");
} else {
console.log("PushManager worker supported")
}
};
const saveSubscription = async subscription => {
console.log("Save Sub")
const SERVER_URL = "http://localhost:4000/save-subscription";
const response = await fetch(SERVER_URL, {
method: "post",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(subscription)
});
return response.json();
};
const urlB64ToUint8Array = base64String => {
const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, "+")
.replace(/_/g, "/");
const rawData = atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
};
const registerServiceWorker = async () => {
return navigator.serviceWorker.register("service.js?"+Math.random()).then((swRegistration) => {
console.log(swRegistration);
return swRegistration;
});
};
const requestNotificationPermission = async (swRegistration) => {
return window.Notification.requestPermission().then(() => {
const applicationServerKey = urlB64ToUint8Array(
"BFPtpIVOcn2y25il322-bHQIqXXm-OACBtFLdo0EnzGfs-jIGXgAzjY6vNapPb4MM1Z1WuTBUo0wcIpQznLhVGM"
);
const options = { applicationServerKey, userVisibleOnly: true };
return swRegistration.pushManager.subscribe(options).then((pushSubscription) => {
console.log(pushSubscription);
return pushSubscription;
});
});
};
const main = async () => {
check();
const swRegistration = await registerServiceWorker();
const subscription = await requestNotificationPermission(swRegistration);
// saveSubscription(subscription);
};
service.js
self.addEventListener("push", function(event) {
if (event.data) {
console.log("Push event!! ", event.data.text());
} else {
console.log("Push event but no data");
}
});
I can think of three reasons that the permission is denied
1) your site is not on https (including localhost that is not on https), the default behaviour from chrome as far as i know is to block notifications on http sites. If that's the case, click on the info icon near the url, then click on site settings, then change notifications to ask
2) if you are on Safari, then safari is using the deprecated interface of the Request permission, that is to say the value is not returned through the promise but through a callback so instead of
Notification.requestPermission().then(res => console.log(res))
it is
Notification.requestPermission(res => console.log(res))
3) Your browser settings are blocking the notifications request globally, to ensure that this is not your problem run the following code in the console (on a secured https site)
Notification.requestPermission().then(res => console.log(res))
if you receive the alert box then the problem is something else, if you don't then make sure that the browser is not blocking notifications requests

connecting to websocket make webworker un-responsive in Microsoft edge

So this is weird, when i try to connect to websocket (this is only a Microsoft edge issue) it makes so on every second page refresh webworker will not accept messages onMessage wont trigger at all:
consider the following:
main.js
var worker = new Worker("webworker.js");
worker.postMessage({ type: 'INIT_SOCKET' });
worker.addEventListener('message', (event) => {
let data = event.data;
if (typeof data === 'string') {
data = JSON.parse(data);
}
if (data.type === 'SOCKET_INITIALIZED') {
console.log('inititalized');
}
});
webworker.js
var io = require('socket.io-client');
var socket;
onmessage = function(event) {
var data = event.data;
console.log('got a event');
if (typeof data === 'string') {
data = JSON.parse(data);
}
switch (data.type) {
case 'INIT_SOCKET':
try {
socket = io('xxxx', { transports: [ 'websocket' ], secure: true }); // this line causes the error
socket.on('connect', function () {
postMessage({
type: Consts.SOCKET_INITIALIZED
});
});
} catch(e) {
console.log('some error ', e);
}
break;
};
};
require does not appear to be defined at Worker context. Use importScripts() to import external scripts into DedicatedWorkerGlobalScope. For example
importScripts("socket.io.js");
Could not determine how to stop io() call from polling and getting error, probably due to 404 error
socket.io.js:7370 WebSocket connection to
'ws://echo.websocket.org/socket.io/?EIO=3&transport=websocket' failed:
Error during WebSocket handshake: Unexpected response code: 404
probably due to being unfamiliar, here, as to how io() is implemented. Though was able to define Socket object within Worker scope.
Approach using WebSocket returns expected result
const worker = new Worker("webworker.js");
worker.addEventListener('message', (event) => {
let data = event.data;
if (typeof data === 'string') {
console.log(data)
}
if (data.type === 'SOCKET_INITIALIZED') {
console.log('inititalized');
}
});
worker.postMessage({
type: 'INIT_SOCKET'
});
importScripts("socket.io.js");
let sock = io();
console.log(sock); // to demonstrate `Socket` is defined
sock.close(); // closing socket here to prevent `404` polling errors
self.socket = void 0;
self.onmessage = function(event) {
var data = event.data;
console.log('got a event');
if (typeof data === 'string') {
data = JSON.parse(data);
}
switch (data.type) {
case 'INIT_SOCKET':
if (!self.socket) {
try {
self.socket = new WebSocket("ws://echo.websocket.org/");
self.socket.onopen = function(e) {
socket.send("WebSocket rocks");
console.log("self.socket event.type:", e.type);
self.postMessage({
type: 'SOCKET_INITIALIZED'
});
};
self.socket.onmessage = function(e) {
console.log(e.data);
self.socket.close()
};
self.socket.onerror = function(e) {
console.log("self.socket error", e);
};
self.socket.onclose = function(e) {
console.log("self.socket event.type", e.type);
};
} catch (e) {
console.log('some error ', e);
}
break;
};
}
};
plnkr http://plnkr.co/edit/zVnLE6qG7Kf4yVSb0aJt?p=preview

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

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.
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.
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.
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/
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!
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();

Categories