首页 文章

Angular Observables和Http

提问于
浏览
11

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

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

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

我知道你订阅了一个observable,但是当需要按顺序发生一系列事情时会发生什么? angular 2 http documentation经历了一个非常简单的例子,即在进行一次调用时更新英雄列表 .

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

3 回答

  • 4

    如何推理Observables?

    Observable处理流 . 流可以是几乎任何东西,但你可以把它们想象成 abstract array of asynchronous events . 这很有用,因为您现在可以更清楚地推理它们:

    • abstract 因为Observable可以生成任何类型的值: String, Boolean, Object

    • array 因为Observable的Operators与JavaScript的数组方法类似: map(), filter(), reduce()

    • of 因为Observable是值的包装器

    • asynchronous 因为Observable可能会也可能不会执行

    • events 因为需要触发Observable

    何时使用Observables?

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

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

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

    我有一个组件,只显示一般主题的消息列表 . 现在,我有一个所有消息都属于的主题 . 如果主题不存在,则应创建该主题 . 消息和主题调用都是通过REST API完成的 . 在非同步世界中,我会按顺序编程 . 消息服务将查看主题是否存在 . 如果没有,那么它有主题服务创建它 . 在有主题后,它会获取该主题中的所有消息 .

    对于您的用例 The Plan 将是: ["(create topic)", "select topic", "show messages"] . messagesabstract arrayselectcreateasynchronous events .

    如何使用Observable?

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

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

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

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

    你可以使用你需要的任何Operators这导致了Observables的下一个重大事件:

    “热”和“冷”可观测量

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

    你可以通过订阅它来触发它,或者使用 subscribe() 方法手动触发它,或者你可以让Angular使用 async pipe(它订阅你)使它成为 hot .

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

    注意变化

    接下来要做的事情(或之前因为我们将在 The Plan 中倒退)是 "select topic" . 观看所选主题的 Value 并通过加载新消息来响应它的变化会很好 . 这可以通过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)
      }
    }
    

    总结

    最后一步是 "(create topic)" 如果没有't exist. Let'假设服务器会在主题不存在时返回错误:

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

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

  • 14

    实际上,Reactive Programming允许创建异步数据流 . 这意味着你可以利用

    Angular2的HTTP支持利用运算符(flatMap,...)将流链接在一起并实现复杂的处理链 . 这意味着您可以使用Reactive Programming / RxJS的所有概念将HTTP请求作为异步数据流的一部分 .

    这里有一个简单的示例,它允许根据表单输入的值执行请求(发生更新时):

    this.inputControl.valueChanges.debounceTime(500).flatMap(
      val => {
        // Execute ab 
        return this.http.get(`http://...?filter=${val}`);
      }).subscribe((data) => {
        this.places = data;
      });
    

    操作员还可以在HTTP上下文中轻松实现几个问题:

    • Ensure to receive the latest when requests are executed in sequence (例如,基于用户输入) . switchMap 运算符的示例,用于在触发新请求时取消先前正在进行的请求
    this.ctrl.valueChanges.switchMap(
      val => {
        return this.http.get(`http://...?filter=${val}`);
      });
    
    • Buffer events and trigger the last one after an amount of time . 在根据输入的最新值执行请求之前等待500ms不活动的示例:
    this.ctrl.valueChanges.debounceTime(500).flatMap(
      val => {
        return this.http.get(`http://...?filter=${val}`);
      });
    
    • Retry when requests fail . 每500毫秒和2秒内重试的样本
    var params = new URLSearchParams();
    params.set('placename_startsWith', searchText);
    params.set('username', 'XXX');
    
    return this.http.get('http://api.geonames.org/postalCodeSearchJSON',
          { search: params })
      .retryWhen(error => error.delay(500))
      .timeout(2000, return new Error('delay exceeded'))
      .map(res => res.json().postalCodes);
    

    以下是一些有关反应式编程的文章可以帮助您:

  • 2

    虽然我不太明白你的问题,但可能 Observable.selectManyObservable.and/thenDo/when 可以帮助你 .

    https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/selectmany.md

    https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/when.md

    在您的情况下,我认为它可以让您创建一个提取和插入的事务 .

相关问题