Angular Observables和Http

eli*_*tbo 11 observable angular

我很难将我的大脑缠绕在Angular的观察者身上.我来自PHP的世界,事情肯定不是异步的.

我有一个组件,只显示一般主题的消息列表.现在,我有一个所有消息都属于的主题.如果主题不存在,则应创建该主题.消息和主题调用都是通过REST API完成的.

在非同步世界中,我会按顺序编程.消息服务将查看主题是否存在.如果没有,那么它有主题服务创建它.在有主题后,它会获取该主题中的所有消息.

我知道你订阅了一个observable,但是当需要按顺序发生一系列事情时会发生什么?的角2的HTTP文档经过当一个呼叫由更新英雄列表的一个非常简单的例子.

零件

export class NotificationListComponent implements OnInit {
    constructor(private _notificationService:NotificationService) {
}

***

ngOnInit() {
    this.getNotifications();
}

getNotifications() {
      this._notificationService.getNotifications()
        .subscribe(
            notifications => this.notifications = notifications,
            error => this.errorMessage = <any>error);
}
Run Code Online (Sandbox Code Playgroud)

通知服务

...    
 getNotifications() {
     //  call the topic service here for general topic??

    return this.http.get('/messages?order[datesent]=DESC')
        .map((res) => {
            return res.json()["hydra:member"];
        })
        .map((notifications:Array<any>) => {
            let result:Array<Notification> = [];
            notifications.forEach((jsonNotification) => {
                var Notification:Notification = {
                    message: jsonNotification.message,
                    topic: jsonNotification.topic,
                    datesent: new Date(jsonNotification.datesent),
                };
                result.push(Notification);
            });
            return result;
        })
        .catch(this.handleError);
}
...
Run Code Online (Sandbox Code Playgroud)

主题服务

  ...
 getGeneralTopic() {
    var generalTopic;

    this.http.get('/topics?name=general')
        .map((res) => {
            return res.json()["hydra:member"][0];
        })
        .do(data => console.log(data))
        .subscribe(generalTopic => res);
}
...
Run Code Online (Sandbox Code Playgroud)

Sas*_*sxa 14

如何推理Observables

Observable处理.流可以是几乎任何东西,但您可以将它们视为异步事件的抽象数组.这很有用,因为您现在可以更清楚地推理它们:

  • abstract,因为Observable可以生成任何类型的值:String, Boolean, Object
  • 数组,因为Observable的Operators工作类似于JavaScript的数组方法:map(), filter(), reduce()
  • ,因为可观察为值的包装(S)
  • 异步因为可观察可能可能不执行
  • 事件因为需要触发Observable

何时使用Observables

您通常在需要执行任务或涉及多个步骤的操作时使用Observable.这可以作为您的起点,您可以根据需要简化或增加复杂性.

你应该有一个"计划"或至少一个模糊的想法,这些步骤应该是什么.听起来很明显,但很多问题都出现了,因为你不知道自己想要什么(;

一旦你计划了一个动作(作为一系列步骤),你可以从任何一端开始,但我认为最好从最后开始.至少在你了解更多之前.

我有一个组件,只显示一般主题的消息列表.现在,我有一个所有消息都属于的主题.如果主题不存在,则应创建该主题.消息和主题调用都是通过REST API完成的.

在非同步世界中,我会按顺序编程.消息服务将查看主题是否存在.如果没有,那么它有主题服务创建它.在有主题后,它会获取该主题中的所有消息.

对于您的用例,该计划将是:["(create topic)", "select topic", "show messages"].messages抽象的阵列,selectcreate异步事件.

如何使用Observable

正如我上面所说,让我们从最后开始 - "show messages".

<div *ngFor="#message of messages"></div>
Run Code Online (Sandbox Code Playgroud)

我们知道我们正在处理Observable.of(messages)(这是你手动创建它的方式).接下来,您需要"填充" 消息,并且可以使用Http返回的服务执行此操作Observable.由于您从服务器获得的消息被Http服务包含在几个"层"中,因此我们可以利用Observable的功能来链接运算符(运算符返回Observable)并获取我们需要的消息:

  getMessages(topic) {
    this.http.get("/messages?topic=" + topic)
      .map(response => response.json())
      // chain other operators here...
      .filter(message => !message.private)
  }
Run Code Online (Sandbox Code Playgroud)

你可以在这里使用你需要的任何操作符 ......这导致了Observables的下一个重要事项:

"热"和"冷" 观察者

Observable 默认是的.这意味着当您创建一个observable时,您只需描述它应该做什么.它不会立即执行这些操作(如同Promises)需要触发它.

你通过订阅手动触发它,或者通过subscribe()方法手动触发它,或者你可以让Angular 用管道(它订阅你)使它变async.

  getMessages(topic) {
    this.http.get("/messages?topic=" + topic)
      .map(response => response.json())
      .subscribe(messages => this.messages = messages);
  }
Run Code Online (Sandbox Code Playgroud)

注意变化

接下来要做的事情(或之前因为我们在计划中倒退)是为了"select topic".观看所选主题的价值并通过加载新消息来响应它的变化会很好.这可以用a来完成Subject.

Subject是一种桥接器或代理,在ReactiveX的某些实现中可用,它既充当观察者又充当Observable.因为它是一个观察者,它可以订阅一个或多个Observable,并且因为它是一个Observable,它可以通过重新发送它来传递它所观察的项目,并且它也可以发出新项目.

我们可以topic$像这样设置:

class ListComponent {
  public messages;
  public topic$ = new Subject();

  constructor(private http: Http) {
    this.getMessages('posts');
    this.topic$
      .subscribe(topic => this.getMessages(topic));
  }

  getMessages(topic: string) {....}

  selectTopic(topic: string) {
    this.topic$.next(topic)
  }
}
Run Code Online (Sandbox Code Playgroud)

包起来

最后一步是"(create topic)"如果一个不存在.假设主题不存在,假设服务器将返回错误:

  getMessages(topic: string) {
    this.http.get(API_URL + topic)
      .map(response => response.json())
      .subscribe(
        messages => this.messages = messages, 
        error => this.createTopic(topic)
      );
  }

  createTopic(topic: string) {
    this.http.post(API_URL + topic, { body: JSON.stringify(topic) })
      .map(response => response.json())
      .subscribe();
  }
Run Code Online (Sandbox Code Playgroud)

这是这个例子的工作人员.正如你所看到的那样,这并不难(50行代码......).您可以轻松移动物品并根据需要创建服务.

  • 这个答案太棒了.你真的帮助我更好地理解了可观察物.[subject](http://reactivex.io/documentation/subject.html)的想法非常简洁,如果没有这篇文章,我就不会想到那个方向.我真的很感激帮助,它让我完成了我需要的任务. (3认同)