How do you (delete/destroy/release) a js Websocket instance?

Viewed 19

Here a stackblitz of the problem:

https://stackblitz.com/edit/angular-ivy-vjezvq?file=src/app/app.component.ts

How the hell do you (delete / destroy / release) a WebSocket instance???

export class MyWebsocketService {

    public url;

    _constructor( URL:string ) {
        this.connect();
    }
    
    connect() {        
        this.ws = new WebSocket(this.url);        
        this.ws.onopen = () => { // blablabla }
        this.ws.onmessage = () => { // blablabla }
        this.ws.onclose = () => { 

            /////// I CANNOT for the life of me destroy that WebSocket instance from memory
            /////// These are all the solutions online:

            this.ws.onopen = null;
            this.ws.onmessage = null;
            this.ws.onclose = null;
            this.ws.onerror = null;
            this.ws.close();
            this.ws = null;
            delete this.ws;

            setTimeout( _ => {
                console.log('Reconnecting...');
                this.connect();
            }, 3000);
        }
    }
}

...

public websocket;

createWebsocketsServices() {
    this.websocket = new MyWebsocketService('wss://whatever');
    
    // HERE I'm changing the URL
    this.websocket = new MyWebsocketService('wss://my-new-url');

    ////////// BUT THE  FIRST WEBSET IS STILL IN MEMORY!!!!!!!
}

ngOnInit(): void {
    this.createWebsocketsServices();
}

None of the solutions I found online actually resolve this issue

Understanding object creation and garbage collection of a NodeJS WebSocket server

WebSocket: How to automatically reconnect after it dies

How do you remove a native websocket handler when setting with ws.onmessage = myFunc; or ws.onopen = function(){}?

1 Answers

When replacing one MyWebsocketService with another one, you'll need to disconnect the former one. Otherwise the web socket stays open, continues to receive messages, and will retain in memory all the callbacks that are registered to events and the things they reference. Overwriting the websocket variable will do nothing to prevent this, it does not "destroy" the object or release its memory, it just removes one reference to the object which would allow the garbage collector to collect the object if it wasn't referenced elsewhere - but it still is referenced from the open socket.

You'll want to do

export class MyWebsocketService {
    public url: string;
    public ws?: WebSocket;

    _constructor(url: string) {
        this.url = url;
    }
    
    connect() {        
        this.ws = new WebSocket(this.url);        
        this.ws.onopen = () => { // blablabla }
        this.ws.onmessage = () => { // blablabla }
        this.ws.onclose = () => { 
            this.ws = null;
        }
    }
    disconnect() {
        this.ws?.close();
    }
}

then

createWebsocketsServices() {
    this.websocket = new MyWebsocketService('wss://whatever');
    this.websocket.connect();
    
    // HERE I'm changing the URL:
    this.websocket.disconnect();
    this.websocket = new MyWebsocketService('wss://my-new-url');
    this.websocket.connect();
}
Related