RxJS-Subject, BehaviorSubject, ReplaySubject, AsyncSubject
1. Subject
直接用subject的next方法传值,所有订阅的observer就会接收到,因为Subject本身是Observable。它会在内部管理一份observer的事件清单
const subject = new Subject();
subject.subscribe({
    next: value => console.log('next: ' + value),
    error: error => console.log('error: ' + error),
    complete: () => console.log('complete!')
});
//  next: 1
//  next: 2
//  next: 3 等待1s
subject.next(1);
subject.next(2);
setTimeout(() => {
    subject.next(3);
}, 1000);
//  这里只会收到`3`,因为只有next(3)是该订阅之后执行的
subject.subscribe({
    next: value => console.log('next: ' + value),
    error: error => console.log('error: ' + error),
    complete: () => console.log('complete!')
});
//  next: 3
2. BehaviorSubject
很多时候我们会希望Subject能代表当前的状态,而不是单纯的事件发送,也就是说如果有一个新的订阅,我们希望Subject能立即给出最新的值,而不是订阅后要等待执行next()才能收到新值。
const subject = new Subject();
subject.subscribe({
    next: value => console.log('next: ' + value),
    error: error => console.log('error: ' + error),
    complete: () => console.log('complete!')
});
//  next: 1
//  next: 2
subject.next(1);
subject.next(2);
setTimeout(() => {
    //	这里不会收到任何消息,因为是在next()之后订阅的
    subject.subscribe({
        next: value => console.log('next: ' + value),
        error: error => console.log('error: ' + error),
        complete: () => console.log('complete!')
    });
}, 1000);
我们希望subject订阅时就能立即收到2,可以用BehaviorSubject 。
BehaviorSubject 跟Subject最大的不同就是BehaviorSubject是用来呈现当前的值,而不是单纯的发送事件。BehaviorSubject会记住最新一次发送的元素,并把该元素当作目前的值,在使用上BehaviorSubject需要传入一个参数来代表默认的状态,示例如下:
const subject = new BehaviorSubject(0); //  0为默认值
subject.subscribe({
    next: value => console.log('next: ' + value),
    error: error => console.log('error: ' + error),
    complete: () => console.log('complete!')
});
//  next: 0
//  next: 100
subject.next(100);
setTimeout(() => {
    subject.subscribe({
        next: value => console.log('next: ' + value),
        error: error => console.log('error: ' + error),
        complete: () => console.log('complete!')
    });
    //  next: 100
}, 1000);
这个示例可以看得出来BehaviorSubject在创建时就需要给定一个状态,并在之后任何一次订阅,就会先送出最新的状态。其实这种行为就是一种状态而非单纯的事件。
3. ReplaySubject
在某些时候我们会希望Subject代表事件,但又能在新订阅时重新发送最后的几个元素,这时我们就可以用ReplaySubject。示例如下
const subject = new ReplaySubject(2); //  重新发送最后两个元素
subject.subscribe({
    next: value => console.log('next: ' + value),
    error: error => console.log('error: ' + error),
    complete: () => console.log('complete!')
});
//  next: 1
//  next: 2
//  next: 3
subject.next(1);
subject.next(2);
subject.next(3);
setTimeout(() => {
    subject.subscribe({
        next: value => console.log('next: ' + value),
        error: error => console.log('error: ' + error),
        complete: () => console.log('complete!')
    });
    //  next: 2
    //  next: 3
}, 1000);
可能会有人认为ReplaySubject(1)是不是就等同于BehaviorSubject,其实是不一样的,BehaviorSubject在建立时就会有起始值,比如BehaviorSubject(0)起始值就是0,BehaviorSubject是代表着状态而ReplaySubject只是事件的重放而已。
4. AsyncSubject
AsyncSubject是最怪的一个变形,他有点像是operator last,会在subject结束后送出最后一个值。其实这个行为跟Promise很像,都是等到事情结束后送出最后一个值。示例如下
const subject = new AsyncSubject();
subject.subscribe({
    next: value => console.log('next: ' + value),
    error: error => console.log('error: ' + error),
    complete: () => console.log('complete!')
});
//  等待1s
//  next: 3
//  complete!
subject.next(1);
subject.next(2);
subject.next(3);
setTimeout(() => {
    subject.complete();
}, 1000);