28

I am using Websockets in pure Javascript and I want to implement Promises into the Websocket functions. I don't get any errors but the Promise doesn't work.

Using the following code I can connect succesful to the socketserver but the Promise seems to be skipped because the output of the alert is always "failed".

Does somebody knows what the problem is in this case? Ps: I did the tests in the latest Google Chrome browser and the latest Mozilla Firefox browser, and I left out some basic checking/error handling for this example.

function Connect()
{
    server = new WebSocket('mysite:1234');

    server.onopen = (function()
    {
        return new Promise(function(resolve, reject) 
        {
            if (true)
            {
                resolve();
            }
            else
            {
                reject();
            }
        });
    }).then = (function()
    {
        alert('succeeed');
    }).catch = (function()
    {
        alert('failed');
    });
}
4
  • What makes you think you can connect successfully? Commented Feb 17, 2017 at 19:34
  • 1
    FYI: Your code will set server.onopen to the last function (the one that alerts failed) - you could change .then and .catch to anything and it would still do the same ... effectively it's the same as var x = ({}).then = ({}).catch = ({hello:'world'}) ... x will be {hello: 'world'} and the intermediate objects with .then and .catch properties are discarded Commented Feb 17, 2017 at 22:05
  • Thanks for the explanation, helpful for sure! Commented Feb 19, 2017 at 20:07
  • stackoverflow.com/a/49533457/1359764 Commented Mar 29, 2018 at 3:45

3 Answers 3

67

Your attempt to use promises with the new connection seems a bit misguided. You will want to return a promise from connect() so you can use it to know when the server is connected.

It seems like you probably want something like this:

function connect() {
    return new Promise(function(resolve, reject) {
        var server = new WebSocket('ws://mysite:1234');
        server.onopen = function() {
            resolve(server);
        };
        server.onerror = function(err) {
            reject(err);
        };

    });
}

Then, you would use it like this:

connect().then(function(server) {
    // server is ready here
}).catch(function(err) {
    // error here
});

or with async/await like this:

async myMethod() {
  try {
      let server = await connect()
      // ... use server
  } catch (error) {
      console.log("ooops ", error)
  }
}
Sign up to request clarification or add additional context in comments.

5 Comments

@Piet - That simply isn't how promises work. Promises are one-shot devices. They only ever fire once. Incoming messages can happen more than once so they are not a good design match for promises. Plus, you don't create a new promise every time a new event occurs. That isn't how promises work at all. You create a promise when you trigger some async operation and you are waiting for the one and only one response from that operation. The promise is then used to monitor that one result. You will just need to use regular callbacks for recurring events.
Doesn't this code have issue when certain error happens? The "onopen" might be called only once, but the "onerror" event stays attached to the websocket indefinitely.
@EricBurel - What issue do you think there would be? Promises are one-shot devices so calling reject() more than once or calling it after resolve() has been called will just ignore the subsequent calls.
@kta - Please post your own code to your own question as nobody here can help you debug your code without seeing it.
Sorry @jfriend00. Let me remove my previous connect from here. There were some issues but I can confirm that it eventually worked.
11

I faced exactly the same problem and created tiny websocket-as-promised library. It returns promises for connecting / disconnecting and sending messages:

const WebSocketAsPromised = require('websocket-as-promised');
const wsp = new WebSocketAsPromised();

// connect
wsp.open('ws://echo.websocket.org')
  .then(() => console.log('Connected.')) 
  // send data and expect response message from server
  .then(() => wsp.sendRequest({foo: 'bar'}))
  .then(response => console.log('Response message received', response))
  // disconnect
  .then(() => wsp.close())
  .then(() => console.log('Disconnected.'));

Concerning messages there are two options:

  1. if you send data and expect response message - you can use promise via .sendRequest() method:

    wsp.sendRequest({foo: 'bar'}); // returns promise
    // actually sends message with unique id: {id: 'xxxxx', foo: 'bar'}
    // promise waits response message with the same id: {id: 'xxxxx', response: 'ok'}
    
  2. if you just want to send message and do not expect response - use .send() method:

    wsp.send(data); // returns undefined
    

2 Comments

How does the server respond to this in a manner that the client expects? Another send to the socket? A return?
Server should respond with a message, containing the id field. For example, server receives request {id: 1, data: 'foo'} and respond with {id: 1, data: 'bar'}.
8

To extend @jfriend00 answer, as his answer tries to create a new connection every time the connect method is called and it does not consider the case where the connection is closed

function getSocket() {

  if (getSocket.server && getSocket.server.readyState < 2) {
    console.log("reusing the socket connection [state = " + getSocket.server.readyState + "]: " + getSocket.server.url);
    return Promise.resolve(getSocket.server);
  }

  return new Promise(function (resolve, reject) {

    getSocket.server = new WebSocket(SOCKET_URL);

    getSocket.server.onopen = function () {
      console.log("socket connection is opened [state = " + getSocket.server.readyState + "]: " + getSocket.server.url);
      resolve(getSocket.server);
    };

    getSocket.server.onerror = function (err) {
      console.error("socket connection error : ", err);
      reject(err);
    };
  });
}

and to use it

getSocket().then(function(server) {
  // do stuff
}).catch(function(err) {
    // error here
});

or with async/await

const socket = await getSocket();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.