在Angular 2中重新订阅一个普遍未被提及的Rx.Subject

时间:2018-01-12 00:18:47

标签: angular typescript rxjs

我不确定,如果我使用的是错误的方法,或者我的编码很糟糕,而是解释我的问题。

我有一个后端组件,我在其中管理websockets数组(因为每个websocket都可以有不同的WS url,或者它们需要单独关闭/打开),对于每个websocket,我想知道它的状态和通过Rx.Subject将其发送到视图(如果它已打开,关闭或者它没有连接所需的数据)

看起来

public class MyTest {

    private static double START = 0;
    private static double END = 100;
    private static double INCREMENT = 0.0001;

    @Test
    public void testFirst() throws Exception {
        long time = System.nanoTime();
        for (double bMI = START; bMI < END; bMI += INCREMENT) {
            first(bMI);
        }
        System.out.println("First  " + (System.nanoTime() - time));
    }

    @Test
    public void testSecond() throws Exception {
        long time = System.nanoTime();
        for (double bMI = START; bMI < END; bMI += INCREMENT) {
            second(bMI);
        }
        System.out.println("Second " + (System.nanoTime() - time));
    }

    private String first(double bMI) {
        String weightStatus = "Underweight";
        if (bMI > 29.9) {
            weightStatus = "Obese";
        } else if (bMI >= 25.0) {
            weightStatus = "Overweight";
        } else if (bMI >= 18.5) {
            weightStatus = "Healthy Weight";
        }
        return weightStatus;
    }

    private String second(double bMI) {
        String weightStatus;
        if (bMI > 29.9) {
            weightStatus = "Obese";
        } else if (bMI >= 25.0) {
            weightStatus = "Overweight";
        } else if (bMI >= 18.5) {
            weightStatus = "Healthy Weight";
        } else {
            weightStatus = "Underweight";
        }
        return weightStatus;
    }
}

这可行。

在我看来,我已经定义了

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;
    }
}

我只用这种方式订阅

hardwareTerminalStateWS: Rx.Subject<ITerminalWebsocketMessage>;

和我视图中的ngOnDestroy

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

取消赞成。

现在主要问题如果我关闭/更改为其他视图,然后返回(例如重新打开并再次订阅)则会抛出错误

&#34; ./hwcomponent类中的错误hwComponent - 内联模板:47:28导致:object unsubscribed&#34;

我应该将Rx.Subject更改为其他类(Observer?)?或者使用不同的方法关闭hardwareTerminalStateWS? 因为如果我不关闭它,下次我再次打开视图时,它会打开第二个hardwareTerminalStateWS并读取每个messeage两次。

1 个答案:

答案 0 :(得分:2)

如果您使用unsubscribe而不是Subject致电Subscription,则无法再使用Subject

有关详细信息,请参阅this answer和Ben Lesh的中篇文章On The Subject Of Subjects

  

如果您希望主题在next完成后对其进行大声和愤怒的错误,您可以直接在主题实例上调用unsubscribe

如果您打算重复某个主题,请拨打unsubscribe上的Subscription(通过调用subscribe返回)。

此外,应该注意的是,在unsubscribe上调用Subject与在unsubscribe上调用Subscription的效果不同。通常,您可以在unsubscribe上致电Subscription,如果您想确保无法重复使用unsubscribe,也可以致电Subject