typescript - abonnere på nytt en tidligere avmeldt Rx.Subject i Angular 2


Jeg er ikke sikker på om jeg bruker en feil tilnærming eller om jeg bare koder dårlig, men til forklaring av mitt problem.

Jeg har en backend-komponent, hvor jeg håndterer et array av websockets (fordi hver websocket kan ha en forskjellig WS-URL, eller de må slås av/på separat), og for hver websocket vil jeg vite tilstanden dens og sende den til en visning gjennom Rx.Subject (om den er åpnet, lukket eller om den ikke har nødvendige data for å opprette en forbindelse)

som ser

public connectDeviceTerminalWebSocket(server: string, port: string): void {
    if (!(server !== null) && !(port !== null)) {

        let websocket: WebSocket = null;

        let wsPosition: number = this.hardwareTerminalwebSockets.findIndex(ws => {
            if (ws.url.includes(server + ':' + port)) {
                websocket = ws;
                return true;
            }
        });

        if (websocket) {
            this.closeHardwareTerminalWebsocket(websocket.url);
        }

        websocket = new WebSocket(`${this.wsProtocol}://${server}:${port}/${this.getToken()}`);

        websocket.addEventListener('close', ws => {
            this.reconnectTerminalWebSocketAfterTimeout();
            this.hardwareTerminalState.next({ 'websocketUrl': websocket.url, 'isConnected': false, 'reason': 'conectionFailed' });
        });

        websocket.addEventListener('open', ws => {
            this.reconnectTerminalWebSocketAfterTimeout();
            this.hardwareTerminalState.next({ 'websocketUrl': websocket.url, 'isConnected': true, 'reason': 'connected' });
        });


        let opened = Rx.Observable
            .fromEvent<void>(websocket, 'open');
        let channelReceived = Rx.Observable
            .fromEvent<MessageEvent>(websocket, 'message')
            .map(event => {
                try {
                    return JSON.parse(event.data);
                } catch (e) {
                    console.error('Parse error: ', e);
                }
                return null;
            });
        channelReceived
            .filter(message => message.message_channel === 'hardware-logger')
            .subscribe(this.hardwareTerminal);


        opened.subscribe(open => this.sendWebSocketTerminalMessageQueue());

        if (wsPosition > -1) {

            this.hardwareTerminalwebSockets[wsPosition] = websocket;
        } else {

            this.hardwareTerminalwebSockets.push(websocket);
        }
    } else {
        this.hardwareTerminalState.next({ websocketUrl: null, isConnected: null, 'reason': 'cantConnect' });
        return;
    }
}

og dette fungerer.

Etter min mening har jeg definert

hardwareTerminalStateWS: Rx.Subject<ITerminalWebsocketMessage>;

som jeg bare abonnerer på en gang på denne måten

this.hardwareTerminalStateWS.subscribe(msg => this.onStateMessage(msg));

og i ngOnDestroy i mitt syn

this.hardwareTerminalWS.unsubscribe();

å avslutte abonnementet på det.

Nå er hovedproblemet hvis jeg lukker/byter til en annen visning, og går tilbake (f.eks. åpner på nytt og abonnerer på det igjen), kaster det en feil

"Feil i ./hwcomponent klasse hwComponent - inline-mal:47:28 forårsaket av: objektet abonnerte ikke lenger"

Bør jeg endre Rx.Subject til en annen klasse (Observer?)? Eller bruke en annen metode for å lukke hardwareTerminalStateWS? For hvis jeg ikke lukker den, neste gang jeg åpner visningen igjen, åpner den en annen hardwareTerminalStateWS og leser hver melding to ganger.

Svar #1

Hvis du kaller unsubscribe på et Subject - i stedet for på et Subscription - kan du ikke lenger bruke Subject.

For mer informasjon, se dette svaret og Ben Leshs Medium-artikkel Om Emner:

Hvis du vil at subjektet skal feile høyt og sint når du next til det etter at det har vært nyttig, kan du kalle unsubscribe direkte på selve subjektinstansen.

Hvis du har tenkt å gjenbruke et emne, kall unsubscribe på Subscription (som returneres fra kallet til subscribe) i stedet.

Det bør også bemerkes at å kalle unsubscribe på Subject ikke vil ha samme effekt som å kalle unsubscribe på Subscription. Vanligvis vil du kalle unsubscribe på Subscription og du vil også kalle unsubscribe på Subject hvis du ønsket å sørge for at det ikke kunne brukes på nytt.

Relaterte artikler