在redux-observable中关闭websocket连接

时间:2018-01-16 13:34:00

标签: rxjs redux-observable

我目前正在使用redux-observable来处理websocket连接,但无法弄清楚处理close事件的最佳方法是什么。

const webSocket$ = Observable.webSocket({
  url: 'ws://localhost:8080'
});

export const fetchMessagesEpic = (action$) =>
  action$.ofType(FETCH.MESSAGES)
    .switchMap((action) =>
      webSocket$
        .catch((err) => { console.log(err);return true; }) <-- I can see the close event here
        .map((msg) => addMessage(msg)));

我是否应该在catch处理它(从那里发送一个新动作,然后在同一个史诗中使用takeUntil

1 个答案:

答案 0 :(得分:1)

如果CloseEvent's Observable.webSocket值为false,则来自rxjs的wasClean(aka WebSocketSubject)仅在错误路径下发送close事件。

rxjs source code

socket.onclose = (e: CloseEvent) => {
  this._resetState();
  const closeObserver = this.closeObserver;
  if (closeObserver) {
    closeObserver.next(e);
  }

  //  v------------------------ Right here
  if (e.wasClean) {
    observer.complete();
  } else {
    observer.error(e);
  }
};

这意味着在您的情况下连接未正确关闭。 CloseEvent上有时会有一个reason字段,可能会或可能不会为您提供见解,或者Chrome开发工具网络和控制台标签可能也有更多。

当远程服务器干净地关闭套接字时,通过传递closeObserver来执行特殊操作的正确方法。直接{ next: func }观察者,或更可能是主体(既是观察者又是观察者)

// a stream of CloseEvents
const webSocketClose$ = new Subject();
const webSocket$ = Observable.webSocket({
  url: 'ws://localhost:8080',
  closeObserver: webSocketClose$
});

export const fetchMessagesEpic = (action$) =>
  action$.ofType(FETCH.MESSAGES)
    .switchMap((action) => {
      const message$ = webSocket$
        .map((msg) => addMessage(msg))
        .catch((e) => Observable.of({
          type: 'SOCKET_ERROR',
          error: e
        }));

      const close$ = webSocketClose$
        .take(1) // you probably only want one
        .map((event) => ({
          type: 'SOCKET_CLOSE_EVENT',
          wasClean: event.wasClean,
          code: event.code,
          reason: event.reason
        }));

      return Observable.merge(message$, close$);
    });

这段代码做了几个假设:

  • 您要处理event.wasClean === true错误。此示例同时使用closeObserver和catch,但您不必这样做。不清楚你是否只关心不洁净的关闭或所有关闭。知道不洁的CloseEvents不是WebSocketSubject可以抛出的唯一错误也很重要。来自socket.onerror的错误以及JS异常发送。
  • 当套接字关闭时,我们对webSocket$的订阅将完成()。如果我们不想webSocket$.takeUntil(webSocketClose$).map(...)

另外我想指出rxjs的catch运算符要求你返回一个Observable,但是你的例子返回了一个布尔值。这会产生错误。如果您只想记录错误而不是处理错误,请使用do运算符。

// BAD
.catch((err) => { console.log(err);return true; })

// GOOD
.do({ error: (err) => console.log(err) })