首页 文章

angular2 rxjs共享订阅未触发

提问于
浏览
1

Angular2 2.0.0-beta.15,Rxjs 5.0.0-beta.2

我有两个简单的rxjs observable,一个是共享的,一个不是(.share()调用它)

我有一个angular2组件,它订阅两个observable并在其模板中显示值,该模板也使用异步管道订阅了observable .

我点击一个按钮在两个带有一些垃圾的observable上设置.next() .

模板更新并显示每个模板的最新值 . 组件中的订阅功能不会为非共享的observable触发 . 为什么?

plunkr:https://plnkr.co/edit/IIWvnTT1zLit1eUNknkk?p=preview

@Component({
    selector: 'my-app',
    template: `
        <div>
            <div>obs1 value: {{ observable1 | async }}</div>
            <div>obs2 value: {{ observable2 | async }}</div>
            <button (click)="randomizeIt()">randomize it</button>

            <br>
            <h3>Question 1</h3>
            Why is obs1's initial value (from startWith) not displayed?

            <h3>Question 2</h3>
            Why does our subscription to obs2 never fire on new values?<br>
            check console.log to see what i mean.
        </div>`,
})
export class App {

    public observable1:Observable<string>;
    public observer1:any;
    public observable2:Observable<string>;
    public observer2:any;

    constructor() {
        this.observable1 = Observable.create(observer => {
            this.observer1 = observer;
        }).startWith("initial obs 1 value").share();

        this.observable1.subscribe((val) => {
            console.log('YOU WILL SEE THIS:', val);
        })

        this.observable2 = Observable.create(observer => {
            this.observer2 = observer;
        }).startWith("initial obs 2 value"); // no share!

        this.observable2.subscribe((val) => {
            console.log('WHY DOES THIS NEVER FIRE ON NEW VALUES?:', val);
        })

    }

    public randomizeIt() {
        let r = Math.random();
        console.log('set both obs to: ', r);
        this.observer1.next(r);
        this.observer2.next(r);
    }   

}

提前致谢!

1 回答

  • 7

    Q1 . Why is obs1's initial value (from startWith) not displayed?

    来自share()文档:

    返回一个可观察序列,该序列共享对基础序列的单个订阅 .

    这意味着,在您的情况下, {{ observable1 | async }}this.observable1.subscribe(....) 共享相同的订阅,当您在构造函数中订阅 observable1 时,您已经启动了序列 . 初始化视图时,已经启动了对 observable1 的订阅并发出了第一个值 . 因此 async 将调用 subscribe() ,但不会获得序列的第一个发射 .

    因此,如果您将订阅移至 ngAfterViewInit() 内,则初始值将转至 async 订阅 .

    ngAfterViewInit(){
      this.observable1.subscribe((val) => {
            console.log('YOU WILL SEE THIS CHANGE:', val);
        })
    }
    

    Q2 . Why does our subscription to obs2 never fire on new values?

    每次订阅 cold Observable时,实际上都会创建一个新的Observable实例 . 创建新实例时,还会创建一个新的观察者实例 . 因此,您对构造函数的订阅是可观察的 instance1 和观察者 instance1async 的订阅是可观察的 instance2 和观察者 instance2 . 因此,当您调用 randomizeIt() 时,将 observer2 调用 instance2 ,该 instance2 绑定到由 async 订阅的可观察 instance2 .

    为了使你的观察“热”:

    let obs = Observable.create(observer => {
        this.observer2 = observer;
    }).startWith("initial obs 2 value");
    this.observable2 = obs.publish();
    
    this.observable2.subscribe((val) => {
        console.log('WHY DOES THIS NEVER FIRE?:', val);
    })
    this.observable2.connect();
    

    Update
    假设你有一个可以发出随机值的observable:

    this.observable3 = Observable.create(observer => {
        observer.next(Math.random());
    });
    

    现在,每次订阅 this.observable3 时,您都会获得一个新的随机值 . 每个订户的 Value 不同 . 因为每个订户都有一个新实例 .

    来自文档:

    有助于将冷酷和热的Observable视为可以观看的电影或表演(“订阅”) . 冷观察:电影 . 热门观察:现场表演 . 热门观察者重播:视频录制的现场表演 . 每当你看电影时,即使所有观看电影的人都看到相同的效果,你的电影也会独立于其他人的电影 . 另一方面,多个观看者共享现场表演 . 如果你迟到现场表演,你会错过一些 . 但是,如果它是在视频上录制的(在RxJS中,这将发生在BehaviorSubject或ReplaySubject上),您可以观看现场表演的“电影” . .publish() . refCount()现场表演是艺术家在没有人观看时退出比赛的表演,并且当 Spectator 中至少有一个人时再次开始播放 .

相关问题