rxjs:订阅者不会触发不同类中的所有更改

tel*_*ion 7 javascript rxjs

我有一个 js 类,它有一个 BehaviorSubject 和一个 Observable。我想订阅另一个类中的 Observable,该类无法正常工作。

//class One: 
export default ClassOne {
     constructor(){
         this._store = new BehaviorSubject({}); 
         this.store = this._store.asObservable(); 
         this.store.subscribe(data => {console.log(data)}) //logs the data, no Problem here
         //{};{ test: { foo: "bar", max: "muster" } };{ test: { foo: "bar", max: "muster" } };...
     }
     addData(data){ this._store.next(data)} //iscalled a few times.

     getStore () {return this.store}        //using a getter Function does not work either

}

//class Two
import class1 from "./class1"; 
ClassTwo {
    constructor(){
        this.one = new ClassOne(); 
        this.one.store.subscribe(data =>{console.log(data)}) //only logs {} once. Is never fired again. 
        this.one.getStore().subscribe(data =>{console.log(data)}) //Same Problem
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我的主要问题是:如何确保订阅者获得 ClassTwo 中的所有更改?

请注意, Observable 已定义并触发一次,但不会收到新更改的通知。

当 ClassOne 是单例时,它会有所不同吗?:

  //class One: 
instance = null; 
export default ClassOne {
     constructor(){
         if (instance === null) {
             instance = this;
         }
         instance._store = new BehaviorSubject({}); 
         instance.store = this._store.asObservable(); 
         instance.store.subscribe(data => {console.log(data)}) //logs the data, no Problem here
     }
     addData(data){ instance._store.next(data)} //iscalled a few times. 
     getStore () {return instance.store}        //using a getter Function does not work either
}
Run Code Online (Sandbox Code Playgroud)

编辑:测试它是否是单例 (使用开玩笑)

beforeAll(() => {
   one = new ClassOne();
});
test("Singleton Test", () => {
  let one2 = new ClassOne();
  expect(one2 instanceof ClassOne).toEqual(true);
  expect(one2).toEqual(one);
  expect(one2 === one).toEqual(true);
});
Run Code Online (Sandbox Code Playgroud)

Edit2:使用添加数据

beforeAll(() => {

one = new ClassOne();
two = new ClassTwo(); 
});
  test("", (done) => {
    one.addData({ test: { foo: "bar", max: "muster" } });
    one.addData({ test: { foo: "bar", max: "muster" } });
    one.addData({ test: { foo: "bar", max: "muster" } });        

    //I just coded this by heart, but the test is somthing like this
    expect(one.getStore()).toEqual(two.one.store);

    //makes sure that the subscriber have enough time
    setTimeout(() => done(), 5000);
  }, 6000);
Run Code Online (Sandbox Code Playgroud)

Edit3:使用共享/共享重播

我已经更改了 getStore() 函数:

//ClassOne
getStore(){ return instance.store.pipe(share()) }
//and I tried: 
getStore(){ return instance.store.pipe(shareReplay()) }

//ClassTwo: 
this.one.getStore().subscribe(data =>{console.log(data)}) 
Run Code Online (Sandbox Code Playgroud)

但问题仍然存在。

Edit4:一些故障排除

因此,经过一些测试和阅读后,我得出结论,构造函数中的订阅无法正常工作。

虽然这不起作用:

   let two = new ClassTwo(); //with the subscription on the store
Run Code Online (Sandbox Code Playgroud)

这有效:

   let two = new ClassTwo(); //without the subscription on the store
   two.subscribeToMyStore(); 

   //subscribeToMyStore: 
   subscribeToMyStore(){
       this.one.store.subscribe(data =>{console.log(data)})
   }
Run Code Online (Sandbox Code Playgroud)

那么为什么我不能在构造函数中进行订阅呢?

为什么它会订阅 ClassOne 而不是 ClassTwo 的构造函数?

tel*_*ion 1

所以问题在于 Jest 的速度。Jest 在执行 classTwo 订阅中的日志之前完成并清理了所有内容。

虽然很奇怪,但对我有用的解决方法是在我的测试中触发complete事件,并且只在complete回调中调用done()。看起来像这样:

 beforeAll(() => {
    one = new ClassOne();
    two = new ClassTwo(); //subcription in constructor
 });
 test("", (done) => {
    one.addData({ test: { foo: "bar", max: "muster" } });
    one.addData({ test: { foo: "bar", max: "muster" } });
    one.addData({ test: { foo: "bar", max: "muster" } });        

    //I just coded this by heart, but the test is something like this
    two.one.store.subscribe({
        complete() {
            //Test the final state of everything here
            //Only call done() here. 
            done();
        },
    });
    setTimeout(
        () => one.store.complete(),   //call complete after a timeout
        1000
    );
 }, 2000);
Run Code Online (Sandbox Code Playgroud)

所以我的要点是:

  • 订阅构造函数是有效的。
  • 确保测试环境在收到更改之前不会破坏 Obeservable 的底层实例。
  • 在setTimeOut 中调用(Behavior)Subject 的complete,并在complete() 的回调中调用done()。
  • 为什么classTwo的订阅那么慢,只有classOne才收到数据,我还是想不明白。