Angular2 http.get (), map (), đăng ký () và mẫu có thể quan sát - hiểu biết cơ bản


170

Bây giờ, tôi có một trang ban đầu nơi tôi có ba liên kết. Khi bạn nhấp vào liên kết 'bạn bè cuối cùng, Thành phần bạn bè phù hợp sẽ được bắt đầu. Trong đó, tôi muốn tìm nạp / nhận danh sách bạn bè của tôi được lưu vào tập tin friends.json. Cho đến bây giờ mọi thứ hoạt động tốt. Nhưng tôi vẫn là người mới sử dụng dịch vụ HTTP của angular2 bằng cách sử dụng khái niệm, bản đồ, đăng ký của RxJs. Tôi đã cố gắng hiểu nó và đọc một vài bài báo nhưng cho đến khi tôi đi vào thực tế, tôi sẽ không hiểu những khái niệm đó một cách đúng đắn.

Ở đây tôi đã thực hiện plnkr đang hoạt động trừ công việc liên quan đến HTTP.

Plnkr

bạn của tôi

 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.

       }
  }

Hãy hướng dẫn và giải thích đúng. Tôi biết nó sẽ rất có lợi cho nhiều nhà phát triển mới.

Câu trả lời:


205

Đây là nơi bạn đã sai:

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

nó nên là:

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

hoặc là

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

Bạn đã phạm phải hai sai lầm:

1- Bạn đã chỉ định bản thân quan sát được this.result. Khi bạn thực sự muốn chỉ định danh sách bạn bè this.result. Cách chính xác để làm điều đó là:

  • bạn đăng ký để có thể quan sát. .subscribelà chức năng thực sự thực thi quan sát được. Phải mất ba tham số gọi lại như sau:

    .subscribe(success, failure, complete);

ví dụ:

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

Thông thường, bạn lấy kết quả từ cuộc gọi lại thành công và gán nó cho biến của bạn. các cuộc gọi lại lỗi là tự giải thích. gọi lại hoàn chỉnh được sử dụng để xác định rằng bạn đã nhận được kết quả cuối cùng mà không có bất kỳ lỗi nào. Trên plunker của bạn, cuộc gọi lại hoàn chỉnh sẽ luôn được gọi sau cuộc gọi lại thành công hoặc lỗi.

2- Sai lầm thứ hai, bạn gọi .json()vào .map(res => res.json()), sau đó bạn gọi nó một lần nữa trên gọi lại thành công của thể quan sát được. .map()là một biến áp sẽ biến đổi kết quả thành bất cứ điều gì bạn trả lại (trong trường hợp của bạn .json()) trước khi nó được chuyển đến cuộc gọi lại thành công, bạn nên gọi nó một lần cho một trong số chúng.


2
ở đây bạn đi plunker của bạn . Tôi đã thay đổi dòng: 21, 23 trên myfriends.ts
Abdulrahman Alsoghayer

1
Điều tôi không hiểu là tại sao lại sử dụng chức năng "bản đồ" ở đây? Chúng tôi chỉ có thể gọi .json về kết quả. Vì vậy, lợi ích của việc làm như vậy là gì?
rubmz

5
Bạn nói đúng @rubmz. Bạn có thể làm điều đó như tôi đã đề cập trong câu trả lời của mình. Nhưng, một lợi ích to lớn là tách biệt logic. Ví dụ, trong dịch vụ của bạn, bạn có một chức năng getFriends(){return http.get('friends.json').map(r => r.json());}. Bây giờ, bạn có thể gọi getFriends().subscribe(...)mà không cần phải gọi .json()mỗi lần.
Abdulrahman Alsoghayer

2
Vâng, đây chỉ là một chút khó hiểu cho người mới. Những gì bản đồ
lầy lội

1
@Abdulrahman, có lẽ bạn cũng sẽ thích thú khi xem câu hỏi này: stackoverflow.com/questions/40505691/ chủ
nyluje

138

Các khái niệm

Có thể quan sát trong các cuộc xử lý ngắn và các sự kiện không đồng bộ. So sánh với những lời hứa này có thể được mô tả là có thể quan sát = lời hứa + sự kiện.

Điều tuyệt vời với các vật quan sát là chúng lười biếng, chúng có thể bị hủy và bạn có thể áp dụng một số toán tử trong chúng (như map, ...). Điều này cho phép xử lý những thứ không đồng bộ một cách rất linh hoạt.

Một mẫu tuyệt vời mô tả sức mạnh tốt nhất của các vật quan sát là cách kết nối đầu vào bộ lọc với danh sách được lọc tương ứng. Khi người dùng nhập các ký tự, danh sách được làm mới. Các đài quan sát xử lý các yêu cầu AJAX tương ứng và hủy các yêu cầu đang thực hiện trước đó nếu một yêu cầu khác được kích hoạt bởi giá trị mới trong đầu vào. Đây là mã tương ứng:

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

( textValuelà điều khiển liên quan đến đầu vào bộ lọc).

Dưới đây là một mô tả rộng hơn về trường hợp sử dụng như vậy: Làm thế nào để theo dõi sự thay đổi hình thức trong Angular 2? .

Có hai bài thuyết trình tuyệt vời tại AngularConnect 2015 và EggHead:

Christoph Burgdorf cũng đã viết một số bài đăng blog tuyệt vời về chủ đề này:

Trong hành động

Trong thực tế liên quan đến mã của bạn, bạn đã trộn lẫn hai cách tiếp cận ;-) Đây là:

  • Quản lý quan sát bằng cách riêng của bạn . Trong trường hợp này, bạn có trách nhiệm gọi subscribephương thức trên có thể quan sát được và gán kết quả vào một thuộc tính của thành phần. Sau đó, bạn có thể sử dụng thuộc tính này trong chế độ xem để lặp qua bộ sưu tập:

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

    Trả về từ cả hai getmapphương thức là kết quả có thể quan sát được (theo cùng một cách so với lời hứa).

  • Hãy quản lý quan sát bằng mẫu Angular . Bạn cũng có thể tận dụng asyncđường ống để ngầm quản lý quan sát được. Trong trường hợp này, không cần phải gọi subscribephương thức một cách rõ ràng .

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

Bạn có thể nhận thấy rằng quan sát là lười biếng. Vì vậy, yêu cầu HTTP tương ứng sẽ chỉ được gọi khi người nghe được đính kèm trên đó bằng subscribephương thức.

Bạn cũng có thể nhận thấy rằng mapphương thức này được sử dụng để trích xuất nội dung JSON từ phản hồi và sau đó sử dụng nó trong quá trình xử lý có thể quan sát được.

Hy vọng điều này sẽ giúp bạn, Thierry


Cảm ơn tất cả các tài liệu tham khảo. Nhưng bạn có thể giúp tôi với plunk của tôi?
nyks

Tôi đã cập nhật câu trả lời của tôi với nhiều chi tiết hơn về mã của bạn. Hy vọng nó sẽ giúp bạn ;-)
Thierry Templier

xin lỗi vì tôi không thể chấp nhận bạn trả lời Câu trả lời rõ ràng hơn nhưng được chấp nhận và đánh giá cao đã giúp tôi hiểu đủ về câu hỏi của mình. Nhưng hy vọng bạn sẽ nhận được lượt truy cập tốt cho câu trả lời rõ ràng của bạn khi bạn có lời giải thích chi tiết hơn. Chấp nhận câu trả lời quá tốt cho cơ sở tốt.
micronyks

2
Thierry Templier đây là một câu trả lời tuyệt vời nhưng đối với tôi, một điều không rõ ràng, tôi đã nghĩ http.get ('friends.json') .map (hồi đáp => respons.json ()) có thể quan sát được <Array <Object >>. Nếu có thì tại sao bạn gửi nó đến đây.result? chúng là các loại khác nhau.
Stav Alfi

@StavAlfi pipescũng là một observables. xem video này: youtube.com/watch?v=bVI5gGTEQ_U được đề xuất bởi thierry để biết thêm thông tin.
thẳng thắn

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

API HTTPClient được giới thiệu trong phiên bản 4.3.0. Đây là một sự phát triển của API HTTP hiện có và có gói riêng @ angular / common / http. Một trong những thay đổi đáng chú ý nhất là bây giờ đối tượng phản hồi là JSON theo mặc định, do đó không cần phải phân tích cú pháp bằng phương pháp bản đồ nữa. Ngay lập tức chúng ta có thể sử dụng như bên dưới

http.get('friends.json').subscribe(result => this.result =result);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.