Angular2 http.get(),map(),subscribe()和可观察模式-基本理解


170

现在,我有一个初始页面,其中有三个链接。一旦单击最后一个“朋友”链接,就会启动适当的朋友组件。在这里,我想获取/获取存放在friends.json文件中的朋友列表。到现在为止一切正常。但是,我仍然是使用RxJs的可观察,映射,订阅概念的angular2 HTTP服务的新手。我试图理解它并读了几篇文章,但是直到我投入实际工作之前,我不会正确地理解那些概念。

在这里,我已经制作了plnkr,除了HTTP相关的工作外,该工作都在工作。

普伦克

myfriends.ts

 import {Component,View,CORE_DIRECTIVES} from 'angular2/core';
 import {Http, Response,HTTP_PROVIDERS} from 'angular2/http';
 import 'rxjs/Rx';
 @Component({
    template: `
    <h1>My Friends</h1>
    <ul>
      <li *ngFor="#frnd of result">
          {{frnd.name}} is {{frnd.age}} years old.
      </li>
    </ul>
    `,
    directive:[CORE_DIRECTIVES]
  })

  export class FriendsList{

      result:Array<Object>; 
      constructor(http: Http) { 
        console.log("Friends are being called");

       // below code is new for me. So please show me correct way how to do it and please explain about .map and .subscribe functions and observable pattern.

        this.result = http.get('friends.json')
                      .map(response => response.json())
                      .subscribe(result => this.result =result.json());

        //Note : I want to fetch data into result object and display it through ngFor.

       }
  }

请正确指导和解释。我知道这将对许多新开发人员如此有益。

Answers:


205

这是您出错的地方:

this.result = http.get('friends.json')
                  .map(response => response.json())
                  .subscribe(result => this.result =result.json());

它应该是:

http.get('friends.json')
                  .map(response => response.json())
                  .subscribe(result => this.result =result);

要么

http.get('friends.json')
                  .subscribe(result => this.result =result.json());

您犯了两个错误:

1-您将可观察对象本身分配给this.result。当您实际上想将好友列表分配给时this.result。正确的方法是:

  • 您订阅观察者。.subscribe是实际执行可观察对象的函数。它需要三个回调参数,如下所示:

    .subscribe(success, failure, complete);

例如:

.subscribe(
    function(response) { console.log("Success Response" + response)},
    function(error) { console.log("Error happened" + error)},
    function() { console.log("the subscription is completed")}
);

通常,您从成功回调中获取结果并将其分配给变量。错误回调是不言自明的。complete回调用于确定您是否已收到最后的结果而没有任何错误。 在您的监听器上,将始终在成功或错误回调之后调用完整的回调。

2-第二个错误,您调用.json().map(res => res.json()),然后在可观察对象的成功回调中再次调用了它。 .map()是一个转换器,可以将结果转换为返回结果(在您的情况下.json()),然后再传递给成功回调,您应该在其中任何一个上调用一次。


2
在这里,你去你的朋克。我更改了线路:
myfriends.ts上的21、23

1
我不明白的是为什么在这里完全使用“地图”功能?我们可以在结果上调用.json。那么这样做的好处是什么?
rubmz

5
您说得对@rubmz。正如我在回答中提到的那样,您可以这样做。但是,分离逻辑是一个巨大的好处。例如,在您的服务中,您具有函数getFriends(){return http.get('friends.json').map(r => r.json());}。现在,您getFriends().subscribe(...)无需.json()每次都可以打电话。
Abdulrahman Alsoghayer '16

2
是的,这对于新手来说有点令人困惑。那神秘的map()是做什么的,什么不是...但是最后我也明白了:)
rubmz

1
@Abdulrahman,也许您也有兴趣看看这个问题:stackoverflow.com/questions/40505691/…–
nyluje

138

概念

短期内的可观察对象解决了异步处理和事件。与承诺相比,这可以描述为可观察的=承诺+事件。

可观察变量的最大优点是它们很懒,可以将它们取消,并且可以在其中应用一些运算符(例如map,...)。这允许以非常灵活的方式处理异步事物。

一个描述最佳观察力的最佳示例是将过滤器输入连接到相应过滤列表的方法。用户输入字符时,将刷新列表。如果输入中的新值触发了另一个AJAX请求,则Observable会处理相应的AJAX请求并取消先前的正在进行的请求。这是相应的代码:

this.textValue.valueChanges
    .debounceTime(500)
    .switchMap(data => this.httpService.getListValues(data))
    .subscribe(data => console.log('new list values', data));

textValue是与过滤器输入关联的控件)。

这是这种用例的更广泛描述:如何在Angular 2中监视表单更改?

AngularConnect 2015和EggHead上有两个精彩的演讲:

Christoph Burgdorf还就该主题写了一些很棒的博客文章:

在行动

实际上,关于您的代码,您混合了两种方法;-)这是它们:

  • 自己管理可观察的对象。在这种情况下,您有责任subscribe在可观察对象上调用方法,并将结果分配给组件的属性。然后,您可以在视图中使用此属性来遍历集合:

    @Component({
      template: `
        <h1>My Friends</h1>
        <ul>
          <li *ngFor="#frnd of result">
            {{frnd.name}} is {{frnd.age}} years old.
          </li>
        </ul>
      `,
      directive:[CORE_DIRECTIVES]
    })
    export class FriendsList implement OnInit, OnDestroy {
      result:Array<Object>; 
    
      constructor(http: Http) {
      }
    
      ngOnInit() {
        this.friendsObservable = http.get('friends.json')
                      .map(response => response.json())
                      .subscribe(result => this.result = result);
       }
    
       ngOnDestroy() {
         this.friendsObservable.dispose();
       }
    }
    

    getmap方法返回的结果都是可观察的,而不是结果(以与诺言相同的方式)。

  • 让我们通过Angular模板管理可观察对象。您还可以利用async管道隐式管理可观察对象。在这种情况下,无需显式调用该subscribe方法。

    @Component({
      template: `
        <h1>My Friends</h1>
        <ul>
          <li *ngFor="#frnd of (result | async)">
            {{frnd.name}} is {{frnd.age}} years old.
          </li>
        </ul>
      `,
      directive:[CORE_DIRECTIVES]
    })
    export class FriendsList implement OnInit {
      result:Array<Object>; 
    
      constructor(http: Http) {
      }
    
      ngOnInit() {
        this.result = http.get('friends.json')
                      .map(response => response.json());
       }
    }
    

您会注意到可观察对象是惰性的。因此,只有使用该subscribe方法在其上附加了侦听器之后,才会调用相应的HTTP请求。

您还可以注意到,该map方法用于从响应中提取JSON内容,然后在可观察的处理中使用它。

希望这对您有帮助,蒂埃里


感谢所有参考。但是你能帮我me一下吗?
nyks,

我用有关您的代码的更多详细信息更新了我的答案。希望它能对您有所帮助;-)
蒂埃里·坦维尔

对不起,我无法接受您的答复。它更清晰,但是被接受和赞赏的答案帮助我对问题有了足够的了解。但希望您有更详细的解释,因为您的明确答案会获得成功。对于良好的基本低估,也接受了答案。
micronyks,2013年

2
Thierry Templier这是一个很好的答案,但我不清楚一件事,我坚信http.get('friends.json').map(response => response.json())返回observable <Array <Object >>。如果是,那么您如何将其发送到this.result?它们是不同的类型。
Stav Alfi

@StavAlfi pipes也是一个observables。观看此视频: thierry建议youtube.com/watch?v=bVI5gGTEQ_U了解更多信息。
candidJ

11
import { HttpClientModule } from '@angular/common/http';

HttpClient API在版本4.3.0中引入。它是现有HTTP API的发展,并具有自己的软件包@ angular / common / http。最显着的变化之一是,现在响应对象默认为JSON,因此不再需要使用map方法进行解析。直接我们可以像下面这样使用

http.get('friends.json').subscribe(result => this.result =result);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.