来自EventEmitter的热门和共享Observable

时间:2015-12-01 10:36:14

标签: javascript angular typescript rxjs

有没有办法从EventEmitter(或Angular 2 alpha 46 / RxJS 5 alpha中提供的等效物)获得热观察?即如果我们在值解析后订阅,则会使用先前解析的值触发。类似于我们总是返回同样的承诺时所拥有的。

理想情况下,只使用Angular 2对象(我稍后会在某处读取轻量级RxJS以删除依赖项),否则导入RxJS就可以了。 AsyncSubject似乎符合我的需要,但它在RxJS 5 alpha中不可用。

我尝试了以下内容,没有成功(从不触发)。关于如何使用它的任何想法?

let emitter = new EventEmitter<MyObj>();
setTimeout(() => {emitter.next(new MyObj());});
this.observable = emitter;
return this.observable.share();

Full plunker here comparing hot and cold

用例:仅访问一些异步对象(例如,在EventEmitter 中合并/包装一系列HTTP调用),但提供已解决的订阅它的任何服务/组件的异步对象,即使它们在解析后订阅(收到HTTP响应)。

编辑:问题不是关于如何合并HTTP响应,而是如何从EventEmitter获得(hot?)observable,以及Angular 2 alpha 46 / RxJS 5 alpha允许在检索/解析异步结果(HTTP只是异步源的一个示例)。 myEventEmitter.share()不起作用(参见上面的plunker),虽然它适用于HTTP返回的Observable(cf plunker from @Eric Martinez)。从Angular 2 alpha 46开始,.toRx()方法不再存在,EventEmitter是可观察的和主体本身。

只要我们总是返回相同的promise对象,这对promises来说效果很好。由于我们已经使用HTTP Angular 2服务引入了观察者,我想避免混合使用promises和观察者(据说观察者比promises更强大,因此它应该允许使用promise进行简单的操作)。

Specs about share()(我还没有找到版本5 alpha的文档 - Angular 2使用的版本) - 处理Angular 2 HTTP服务返回的Observable,而不是在EventEmitter上工作。

编辑:明确了为什么不使用HTTP返回的Observable,并补充说不直接使用RxJS会更好。

编辑:更改说明:关注的是多个订阅,而不是合并HTTP结果。

谢谢!

2 个答案:

答案 0 :(得分:3)

您似乎描述的功能不是冷可观察的功能,而是Rx.BehaviourSubject以上的功能。看看这里有关于Rxjs主题的解释:https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/subjects.md

我引用那里:

  

BehaviourSubject类似于ReplaySubject,只是它只存储了它发布的最后一个值。 BehaviourSubject在初始化时也需要默认值。当主体尚未接收到其他值时,将该值发送给观察者。这意味着除非主题已经完成,否则所有订阅者将在订阅时立即收到值。

Rx.AsyncSubject与承诺的行为最接近:

  

AsyncSubject类似于Replay和Behavior主题,但它只存储最后一个值,并且只在序列完成时才发布它。您可以在源可观察源很热的情况下使用AsyncSubject类型,并且可以在任何观察者可以订阅它之前完成。在这种情况下,AsyncSubject仍然可以提供最后一个值并将其发布给任何未来的订阅者。

还有两条评论:

  • 在您的plunker中:this._coldObservable = emitter.share();。使用share返回一个热门观察者!
  • EventEmitter实际上首先扩展了主题

更新:Rx.Observable

周围包装一个EventEmitter
function toRx ( eventEmitter ) {
  return Rx.Observable.create(function ( observer ) {
    eventEmitter.subscribe(function listener ( value ) {observer.onNext(value)});
    // Ideally you also manage error and completion, if that makes sense with Angular2
    return function () {
      /* manage end of subscription here */
    };
  };
)
}

获得Rx.Observable之后,您可以随意应用share()shareReplay(1)

我敢打赌,Angular团队迟早会提出一项强化功能,但如果你不想等待,你可以自己动手。

答案 1 :(得分:1)

ReplaySubject正在做我想要的事情。 @robwormald提供了一个关于gitter的工作示例,我稍加修改以更好地演示。

公开HTTP响应:

import {Injectable} from 'angular2/angular2';
import {Http} from 'angular2/http';
import {ReplaySubject} from '@reactivex/rxjs/dist/cjs/Rx'

@Injectable()
export class PeopleService {
  constructor(http:Http) {
    this.people = new ReplaySubject(1);

    http.get('api/people.json')
      .map(res => res.json())
      .subscribe(this.people);
  }
}

多次订阅:

// ... annotations
export class App {
  constructor(peopleService:PeopleService) {

    people.subscribe(v => {
      console.log(v)
    });

    //some time later

    setTimeout(() => {
      people.subscribe(v => {
        console.log(v)
      });
      people.subscribe(v => {
        console.log(v)
      });
    },2000)
  }
}

Full plunker

编辑:BehaviorSubject是另一种选择。在此用例中,差异是初始值,例如,如果我们想在使用HTTP响应进行更新之前显示缓存中的内容。