Angular Observables和Http [英] Angular Observables and Http

查看:69
本文介绍了Angular Observables和Http的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很难将自己的大脑包裹在Angular的可观测对象中.我来自PHP的世界,那里的事物肯定不是异步的.

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

在非异步世界中,我将按顺序对其进行编程.消息服务将查看该主题是否存在.如果不是,则使用主题服务来创建它.有了主题之后,便会获取该主题内的所有消息.

我了解您订阅了一个可观察的东西,但是当需要一系列需要顺序发生的事情时会发生什么呢? Angular 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);
}

通知服务

...    
 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);
}
...

主题服务

  ...
 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);
}
...

解决方案

如何推断可观测对象?

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

  • 抽象 ,因为Observable可以产生任何类型的值:String, Boolean, Object
  • 数组 ,因为Observable具有 Operators 可以正常工作与JavaScript的数组方法类似:map(), filter(), reduce()
  • of ,因为Observable是值的包装器
  • 异步 ,因为可观察到的可能可能不会执行
  • 事件 ,因为需要触发可观察对象

何时使用 Observables ?

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

您应该有一个计划"或至少一个模糊的想法,这些步骤应该是什么.听起来很明显,但是由于您不知道想要什么,所以会出现许多问题/问题(;

一旦您计划了一个动作(作为一系列步骤),则可以从任一端开始,但是我认为最好从结尾开始.至少直到您了解更多.

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

在非异步世界中,我将按顺序对其进行编程.消息服务将查看该主题是否存在.如果不是,则使用主题服务来创建它.拥有主题之后,它将获取该主题内的所有消息.

对于您的用例,计划为:["(create topic)", "select topic", "show messages"]. messages 抽象数组 selectcreate 异步事件 .

如何使用可观察?

如上所述,让我们从结尾开始-"show messages".

<div *ngFor="#message of messages"></div>

我们知道我们正在处理Observable.of(messages)(这是您手动创建它的方式).接下来,您需要填充"邮件的,并且可以使用返回ObservableHttp服务来做到这一点.由于您从服务器获取的消息通过Http服务包裹在多个层"中,因此我们可以将Observable的功能运用到链式操作员(操作员返回Observable)并获取我们需要的消息:

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

您可以在此处使用所需的任何运算符 ...这将引发关于Observables的下一件大事:

热"和冷" 可观察物

默认情况下,可观察项为 .这意味着,当您创建一个可观察对象时,您只需描述它应该做什么.它不会立即执行这些操作(就像Promises一样),需要触发它.

您可以通过订阅来触发它,可以使用subscribe()方法手动进行,也可以让Angular使用async管道使其成为 hot (确实可以订阅给你).

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

关注变化

接下来要做的一件事情(或之前要做的事情,因为我们在计划中倒退了)是"select topic".观看所选主题的值并通过加载新消息来响应它的更改,将是很好的选择.可以使用 Subject .

主题是一种桥梁或代理,可在ReactiveX的某些实现中用作观察者和可观察对象.因为它是观察者,所以可以订阅一个或多个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)
  }
}

总结

如果不存在,最后一步是"(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();
  }

在此示例中,是工作中的矮人.如您所见,这并不难(50行代码...).您可以轻松地四处移动并在需要的地方创建服务.

I'm having a hard time wrapping my brain around observables in Angular. I'm coming from the world of PHP, where things are definitely not async.

I have a component that simply displays a list of messages for a general topic. For now, I have one topic that all messages belong to. If the topic doesn't exist, then it should be created. The message and topic calls are all done through a REST api.

In a non-async world, I would program it in order. The message service would see if the topic exists. If it doesn't, then it has the topic service create it. After it has the topic, it then fetches all of the messages within that topic.

I understand that you subscribe to an observable, but what happens when there needs to be a series of things that need to happen in order? The angular 2 http documentation goes through a very simple example of updating the hero list when one call is made.

Component

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);
}

Notification Service

...    
 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);
}
...

Topic Service

  ...
 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);
}
...

解决方案

How to reason about Observables?

Observables deal with streams. Streams can be pretty much anything, but you can think of them as abstract array of asynchronous events. This is useful because you can now reason about them more clearly:

  • abstract because Observable can produce a value of any type: String, Boolean, Object
  • array because Observable has Operators that work similar to JavaScript's array methods: map(), filter(), reduce()
  • of because Observable is a wrapper for value(s)
  • asynchronous because Observable may or may not execute
  • events because Observable needs to be triggered

When to use Observables?

You want to use Observables typically when you need to perform a task or an action that involves several steps. This can be your starting point, you can later simplify or increase complexity as needed.

You should have a "plan" or at least a vague idea what those steps should be. Sounds obvious, but many problems/issues occur because you don't know what you want (;

Once you have planned an action (as an array of steps) you can start from either end, but I think it's better to start from the end. At least until you learn more.

I have a component that simply displays a list of messages for a general topic. For now, I have one topic that all messages belong to. If the topic doesn't exist, then it should be created. The message and topic calls are all done through a REST api.

In a non-async world, I would program it in order. The message service would see if the topic exists. If it doesn't, then it has the topic service create it. After it has the topic, it then fetches all of the messages within that topic.

For your use case The Plan would be: ["(create topic)", "select topic", "show messages"]. messages are abstract array, select and create are asynchronous events.

How to use an Observable?

As I said above, let's start from the end - "show messages".

<div *ngFor="#message of messages"></div>

We know we're dealing with Observable.of(messages) (this is how you would manually create it). Next, you need to 'fill' the stream of messages, and you can do it with Http service that returns Observable. Since messages you get from the server are wrapped in several "layers" by Http service, we can leverage ability of Observable to chain operators (operators return Observable) and get to the messages we need:

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

You can use whatever Operators you need here... which leads to the next big thing about Observables:

"Hot" and "Cold" Observables

Observables are cold by default. This means that when you create an observable you just describe what it should do. It won't execute these actions immediately (like Promises do) it needs to be triggered.

You trigger it by subscribing to it, either manually with subscribe() method, or you can let Angular make it hot with async pipe (which does subscribing for you).

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

Watching for changes

Next thing to do (or previous since we're going backwards in The Plan) is to "select topic". It would be nice to watch the value of selected topic and respond to it's change by loading new messages. This can be done with a Subject.

A Subject is a sort of bridge or proxy that is available in some implementations of ReactiveX that acts both as an observer and as an Observable. Because it is an observer, it can subscribe to one or more Observables, and because it is an Observable, it can pass through the items it observes by reemitting them, and it can also emit new items.

We can setup topic$ to do this like so:

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)
  }
}

Wrap up

Last step is to "(create topic)" if one doesn't exist. Let's assume server would return an error if topic doesn't exist:

  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();
  }

Here's the working plunker with this example. As you can see it's not hard to do (50-ish lines of code...). You can easily move things around and create services where you need.

这篇关于Angular Observables和Http的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆