3

Here's my methods to open/close socket connection:

methods: {
  connect () {
    this.$socket.onopen = () => {
      this.status = 'connected'
      this.$socket.onmessage = ({data}) => {
        this.$socket.send(this.message)
        console.log({ event: "Recieved message", data })
      }
    }
    this.$socket.onclose = (e) => {
      console.log('Socket is closed. Reconnect will be attempted in 1 second.')
      setTimeout(() => {
        this.connect()
      }, 1000)
    }
  },
  disconnect () {
    this.$socket.close()
    this.status = 'disconnected'
  }
}

I'm not using socket.io etc, just built in Websocket object. When i manually call disconnect () method - it closes the connection as expected, but when i send message again - it says that connection is closed. Since i call connect () in a mounted, then it won't reconnect if i don't refresh the page.

I've tried using watcher:

watch: {
  '$socket': 'connect'
}

But no effect. Is there a way to watch for websocket connection status? If it's closed - call connect (), if it's error'ed - call connect () to reconnect it.

Alexander Kim
  • 17,304
  • 23
  • 100
  • 157

2 Answers2

2

Your connect() method does nothing to "reconnect" to the WebSocket server. So calling this.connect() simply rewrites your onopen handler.

You have to take the steps necessary to reconnect to the WebSocket server. The most excellent answer to this question does a great job of explaining a great structure for your code:

vue: emitting global events from websocket listener

Unfortunately, it doesn't answer your specific question. So I've forked the sandbox from that answer and added the modified code below that allows you to achieve your goal.

import Vue from "vue";

const url = "wss://echo.websocket.org";
let socket;

const emitter = new Vue({
  methods: {
    send(message) {
      if (1 === socket.readyState) socket.send(message);
    },
    close() {
      if (1 === socket.readyState) {
        emitter.$emit("message", "Closing Socket.");
        socket.close();
        socket = null; // prevent memory leak
      }
    },
    connect() {
      socket = new WebSocket(url);
      socket.onmessage = function(msg) {
        emitter.$emit("message", msg.data);
      };
      socket.onerror = function(err) {
        emitter.$emit("error", err);
      };
      emitter.$emit("message", "Openning Socket.");
    }
  }
});

emitter.connect();

export default emitter;

To see how this service is used, check out index.js in the running sample is here: https://codesandbox.io/s/ry4993q654

Randy Casburn
  • 13,840
  • 1
  • 16
  • 31
  • Thanks, i've noticed that my `connect()` was useless, because i didn't used `new Websocket()` instance to open it. Your answer suggests to create a new file, e.g. socket.js and importing it in my component? like `import emitter from './socket'` Also what if i want to open connection only if user is logged in? – Alexander Kim Dec 03 '18 at 18:29
  • ref the new file question, look at the structure of the solution in the codesanbox. That should answer that question (`import Socket from './socket'`). Ref logged in user: call `Socket.connect()` in your log-in success handers. – Randy Casburn Dec 03 '18 at 18:39
  • btw, what you have done, is called event bus (publish/subscribe pattern)? – Alexander Kim Dec 05 '18 at 16:16
  • And it is a common pattern in modern asynchronous environments - like a browser. – Randy Casburn Dec 05 '18 at 16:19
  • Can i ask you one more question about the last line in `connect()` method: `emitter.$emit("message", "Openning Socket.");` - what purpose it serves? Also you've used same event name `message` multiple times, if i place a listener to `message` event, then it would listen all these events? – Alexander Kim Dec 06 '18 at 18:31
  • Don't mind the Qs at all. Last line in connect serves no purpose other than logging and can be removed if not needed. RE: `message`: Yes, you can listen for the event name "message" and can handle all events emitted with that name. – Randy Casburn Dec 07 '18 at 00:12
0

You should check the close status code before reconnecting. e.code === 1e3 || e.code === 1001 || e.code === 1005

Nike
  • 97
  • 6