如何确保对观察者的订阅调用最初获得最新值?

时间:2016-04-02 11:37:34

标签: javascript angular typescript rxjs

我正在使用rxjs和Angular 2以及Typescript。我想在多个组件之间共享一个共同的Web资源(一个"项目"在我的应用程序的上下文中,基本上是一个JSON文档)。为了实现这一目标,我引入了一个公开可观察的服务,该服务将由所有客户共享:

/**
 * Handed out to clients so they can subscribe to something.
 */
private _observable : Observable<Project>;

/**
 * Used to emit events to clients.
 */
private _observer : Observer<Project>;

constructor(private _http: Http) {
    // Create observable and observer once and for all. These instances
    // are not allowed to changed as they are passed on to every subscriber.
    this._observable = Observable.create( (obs : Observer<Project>) => {
        this._observer = obs;
    });
}

客户现在只需获取对_observable的引用并订阅它。

/**
 * Retrieves an observable that always points to the active
 * project.
 */
get ActiveProject() : Observable<Project> {
    return (this._observable);
}

当某个组件决定实际加载项目时,它会调用以下方法:

/**
 * @param id The id of the project to set for all subscribers
 */
setActiveProject(id : string) {
    // Projects shouldn't change while other requests are in progress
    if (this._httpRequest) {
        throw { "err" : "HTTP request in progress" };
    }

    this._httpRequest = this._http.get('/api/project/' + id)
        .catch(this.handleError)
        .map(res => new Project(res.json()));

    this._httpRequest.subscribe(res => {
        // Cache the project
        this._cachedProject = res;
        // Show that there are no more requests
        this._httpRequest = null;
        // Inform subscribers
        this._observer.next(this._cachedProject)

        console.log("Got project");
    });
}

它基本上执行HTTP请求,将JSON文档转换为&#34;适当的&#34;实例并调用this._observer.next()通知所有订阅者有关更改的信息。

但是如果在之后订阅已经发生了HTTP请求,则在发出新的HTTP请求之前看不到任何内容。我发现在rxjs中有某种缓存(或重放?)机制似乎可以解决这个问题,但我无法弄清楚如何使用它。

tl; dr :如何确保观察者对subscribe的调用最初获得最新值?

额外的问题:通过&#34;将观察者拉出观察者&#34; (在构造函数中),我基本上创建了一个主题吗?

2 个答案:

答案 0 :(得分:3)

那是BehaviorSubject做什么

import { BehaviorSubject } from 'rxjs/subject/BehaviorSubject';
...
obs=new BehaviourSubject(4);
obs.subscribe(); //prints 4
obs.next(3); //prints 3
obs.subscribe(); //prints 3

答案 1 :(得分:1)

我通常使用shareReplay(1)实现此目的。使用带有1作为参数的运算符将确保发出的最新值将保留在缓冲区中,因此当有新订阅者时,该值立即传递给它。您可以查看documentation

var interval = Rx.Observable.interval(1000);

var source = interval
    .take(4)
    .doAction(function (x) {
        console.log('Side effect');
    });

var published = source
    .shareReplay(3);

published.subscribe(createObserver('SourceA'));
published.subscribe(createObserver('SourceB'));

// Creating a third subscription after the previous two subscriptions have
// completed. Notice that no side effects result from this subscription,
// because the notifications are cached and replayed.
Rx.Observable
    .return(true)
    .delay(6000)
    .flatMap(published)
    .subscribe(createObserver('SourceC'));

function createObserver(tag) {
    return Rx.Observer.create(
        function (x) {
            console.log('Next: ' + tag + x);
        },
        function (err) {
            console.log('Error: ' + err);
        },
        function () {
            console.log('Completed');
        });
}

// => Side effect
// => Next: SourceA0
// => Next: SourceB0
// => Side effect
// => Next: SourceA1
// => Next: SourceB1
// => Side effect
// => Next: SourceA2
// => Next: SourceB2
// => Side effect
// => Next: SourceA3
// => Next: SourceB3
// => Completed
// => Completed
// => Next: SourceC1
// => Next: SourceC2
// => Next: SourceC3
// => Completed
  

额外的问题:通过&#34;将观察者拉出观察者&#34; (在   构造函数),我基本上创建了一个主题吗?

我不确定你的意思,但不是。主体既是观察者又是可观察者,具有特定的语义。仅仅将观察者从观察者中拉出来是不够的。正如你所说。对于主题语义,请看这里:What are the semantics of different RxJS subjects?