2

Currently creating an application using Angular, socket.io and express. However, I run in an async issue which I have a hard time getting a solution for. Here is the code:

  export class WebsocketService {

  this.socket;

  public connect() {
    const token = sessionStorage.getItem('token');
    this.socket = io('http://localhost:3000', { query: { token: token } });
  }

  public getSocket () {

      // this function should only return this.socket when it is available

      return this.socket;

  }

The idea is that first somewhere in the application somewhere there is connected once with the websocket, the io functions is thus called once:

    this.socket = io('http://localhost:3000', { query: { token: token } });

Then in rest of the application the this.socket property should be passed around. However, this.socket should always return the object and should wait for it if it isn't present.

The implementation should also deal with the other parts of the application who try to call getSocket and get returned undefined. Basically, getSocket should never return undefined it should wait for connection and then return this.socket.

I tried playing around with promises a bit but I can't seem to find an elegant solution.

4
  • You mean the promise should wait for someone calling connect() on the service? Commented Aug 7, 2018 at 14:29
  • If io immediately returns a socket (as it appears to in the code above), why would you need a promise? Just construct it on demand (or in connect if you prefer) and return it as needed...? Commented Aug 7, 2018 at 14:42
  • io is async so it doesn't immediately return Commented Aug 7, 2018 at 14:42
  • @WillemvanderVeen - Well, your code treats it like it does. Commented Aug 7, 2018 at 15:20

2 Answers 2

6

I do not know why you need the connect method , but here is one approach

export class WebsocketService {

  getSocket() {

    // this function should only return this.socket when it is available

    if (!this.socket || (this.socket && this.socket.disconnected)) {

      this.socket = new Promise((resolve, reject) => {

        const token = sessionStorage.getItem('token');
        const s = io('http://localhost:3000', { query: { token: token } });

        s.on('connect', () => {
          console.log(socket.connected); // true
          resolve(s);
        });

        s.on('disconnect', () => {
          console.log(socket.disconnect); // true
          reject(s);
        });
      });
    }

    return this.socket;
  }
}

Then, usage is:

service.getSocket().then(socket => {
    // Use the socket
});

Or with async/await:

const socket = await service.getSocket();
// Use the socket
Sign up to request clarification or add additional context in comments.

Comments

0
export class WebsocketService {
    this.socket = io('http://localhost:3000', { query: { token: token }})
    public getSocket () {
        return new Promise((res) => {
           while (!this.socket.connected) {}
           res(this.socket)
        })
    }
}

then call: service.getSocket().then((socket) => {})

Only give you the socket when it's connected. This assumes that the socket will be able to reconnect, but some errors can be expected if never able to reconnect.

6 Comments

Busy waits are never a good idea. In browser-based JavaScript code on the main UI thread (where Angular runs), they're a particularly bad idea.
Ok, I should probably add a timeout so !this.socket.connected isn't evaluated constantly. But, the code execution isn't blocked because it's a Promise. I wrote this with minimal knowledge of the API, but from what I understood the Socket object attempts to reconnect infinite times whenever it loses a connection. If it can't reconnect ever, then some error handling needs to be put in place.
"But, the code execution isn't blocked because it's a Promise." No, that isn't how promises work. Promises are for observing asynchronous completions. They don't make something synchronous asynchronous. Your getSocket will never return, locking up the UI of the browser.
If this.socket.connected is false when time originates, then this.socket.connected is true after a variable amount of seconds, that is a proxy for an asynchronous event.
Thanks, I didn't understand that a 'busy-wait' would block all other execution. I suppose when I learned this construct I would have been instructed to put a sleep or timeout in the loop, and forgetting this, it breaks.
|

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.