使用Subject.create创建一个Rx.Subject,允许onNext无订阅

时间:2016-01-18 01:03:40

标签: rxjs

使用Rx.Subject创建Subject.create(observer, observable)时,Subject非常懒惰。当我尝试在没有订阅的情况下使用subject.onNext时,它不会传递消息。如果我先subject.subscribe(),我可以立即使用onNext

我们说我有一个Observer,就像这样创建:

function createObserver(socket) {
  return Observer.create(msg => {
    socket.send(msg);
  }, err => {
    console.error(err);
  }, () => {
    socket.removeAllListeners();
    socket.close();
  });
}

然后,我创建了一个接受消息的Observable:

function createObservable(socket) {
  return Observable.fromEvent(socket, 'message')
                   .map(msg => {
                     // Trim out unnecessary data for subscribers
                     delete msg.blobs;
                     // Deep freeze the message
                     Object.freeze(msg);
                     return msg;
                   })
                   .publish()
                   .refCount();
}

使用这两个功能创建主题。

observer = createObserver(socket);
observable = createObservable(socket);
subject = Subject.create(observer, observable);

通过此设置,我无法立即subject.onNext(即使我不关心订阅)。这是设计的吗?什么是一个好的解决方法?

这些实际上是TCP套接字,这就是为什么我还没有依赖超级光滑的websocket主题。

1 个答案:

答案 0 :(得分:3)

基本解决方案,在使用ReplaySubject订阅之前缓存nexts:

我认为您要做的就是使用ReplaySubject作为观察者。

const { Observable, Subject, ReplaySubject } = Rx;

const replay = new ReplaySubject();

const observable = Observable.create(observer => {
  replay.subscribe(observer);
});

const mySubject = Subject.create(replay, observable);


mySubject.onNext(1);
mySubject.onNext(2);
mySubject.onNext(3);

mySubject.subscribe(x => console.log(x));

mySubject.onNext(4);
mySubject.onNext(5);

结果:

1
2
3
4
5

套接字实现(例如,不要使用)

...但如果你正在考虑做一个Socket实现,它会变得更加复杂。这是一个有效的套接字实现,但我不建议您使用它。相反,我建议你使用rxjs-dom中的一个社区支持的实现(如果你是RxJS 4或更低版本)或RxJS 5的一部分,两者都是我帮助过了。

function createSocketSubject(url) {
  let replay = new ReplaySubject();
  let socket;

  const observable = Observable.create(observer => {
    socket = new WebSocket(url);

    socket.onmessage = (e) => {
      observer.onNext(e);
    };

    socket.onerror = (e) => {
      observer.onError(e);
    };

    socket.onclose = (e) => {
      if (e.wasClean) {
        observer.onCompleted();
      } else {
        observer.onError(e);
      }
    }

    let sub;
    socket.onopen = () => {
      sub = replay.subscribe(x => socket.send(x));      
    };
    return () => {
      socket && socket.readyState === 1 && socket.close();
      sub && sub.dispose();
    }
  });

  return Subject.create(replay, observable);
}

const socket = createSocketSubject('ws://echo.websocket.org');

socket.onNext('one');
socket.onNext('two');
socket.subscribe(x => console.log('response: ' + x.data));
socket.onNext('three');
socket.onNext('four');

Here's the obligatory JsBin