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
nexttil det etter at det har vært nyttig, kan du kalleunsubscribedirekte 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.