Andrea
Posted on Apr 9, 2020

Wait for the WebSocket connection to be open, before sending a message

Sometimes when you open a new WebSocket connection and try to send a message, you can receive an Error reporting something like this: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state., because the connection is not open yet.

To avoid that, I saw some people suggesting to send the message on the onopen event; something like:

socket.onopen = () => socket.send(message)

This approach, though, only works if you need to trigger send() once (on open).

A more flexible approach would be to wait for the connection to be open (if it's not already).

The waitForOpenConnection function, in the example below, returns a Promise that resolves when the connection is finally open, checking it every n milliseconds. If, after a given number of checks, the connection is still not open, the Promise is rejected. In the sendMessage function, you can see an example of the usage.

const waitForOpenConnection = (socket) => {
  return new Promise((resolve, reject) => {
    const maxNumberOfAttempts = 10
    const intervalTime = 200 //ms

    let currentAttempt = 0
    const interval = setInterval(() => {
      if (currentAttempt > maxNumberOfAttempts - 1) {
        clearInterval(interval)
        reject(new Error('Maximum number of attempts exceeded'))
      } else if (socket.readyState === socket.OPEN) {
        clearInterval(interval)
        resolve()
      }
      currentAttempt++
    }, intervalTime)
  })
}

const sendMessage = async (socket, msg) => {
  if (socket.readyState !== socket.OPEN) {
    try {
      await waitForOpenConnection(socket)
      socket.send(msg)
    } catch (err) {
      console.error(err)
    }
  } else {
    socket.send(msg)
  }
}

Link to the GitHub gist