Angular2 http.get (), map (), subscribe () и наблюдаемый шаблон - базовое понимание


170

Теперь у меня есть начальная страница, где у меня есть три ссылки. Как только вы нажмете на последнюю ссылку «друзья», появится соответствующий компонент друзей. Там я хочу получить / просмотреть список моих друзей в файле friends.json. До сих пор все работает отлично. Но я все еще новичок в HTTP-сервисе angular2, использующем концепцию RxJs «карта, подписка». Я пытался понять это и прочитал несколько статей, но пока я не приступлю к практической работе, я не пойму эти концепции должным образом.

Здесь я уже сделал plnkr, который работает, кроме работы, связанной с HTTP.

Plnkr

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.

       }
  }

Пожалуйста, направьте и объясните правильно. Я знаю, что это будет очень полезно для многих новых разработчиков.

Ответы:


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

Обычно вы берете результаты из обратного вызова success и присваиваете его своей переменной. обратный вызов ошибки не требует пояснений. полный обратный вызов используется для определения того, что вы получили последние результаты без каких-либо ошибок. На вашем поршне полный обратный вызов всегда будет вызываться после успешного завершения или обратного вызова с ошибкой.

2- Вторая ошибка, вы позвонили .json()на .map(res => res.json()), то вы снова назвали его на успех обратного вызова наблюдаемых. .map()это преобразователь, который преобразует результат во все, что вы возвращаете (в вашем случае .json()), прежде чем он будет передан обратному вызову успеха, вы должны вызывать его один раз на любом из них.


2
здесь вы идете свой поршень . Я изменил строки: 21, 23 на myfriends.ts
Абдулрахман Аутгайер

1
Чего я не понял, так это зачем вообще использовать здесь функцию «карта»? Мы могли бы просто позвонить .json о результате. Так какая польза от этого?
rubmz

5
Вы правы @rubmz. Вы можете сделать это, как я уже упоминал в своем ответе. Но одно огромное преимущество - это разделение логики. Например, в вашем сервисе у вас есть функция getFriends(){return http.get('friends.json').map(r => r.json());}. Теперь вы можете звонить getFriends().subscribe(...)без необходимости звонить .json()каждый раз.
Абдулрахман Аутхейер

2
Да, это немного сбивает с толку новичков. Что делает таинственная карта (), а что нет ... Но, наконец, я тоже это получил :)
rubmz

1
@Abdulrahman, может быть, вам будет интересно посмотреть и на этот вопрос: stackoverflow.com/questions/40505691/…
nyluje

138

Концепции

Наблюдаемые в коротких решениях асинхронной обработки и событий. По сравнению с обещаниями это можно описать как наблюдаемые = обещания + события.

Что замечательно с наблюдаемыми, так это то, что они ленивы, их можно отменить, и вы можете применить к ним некоторые операторы (например map, ...). Это позволяет обрабатывать асинхронные вещи очень гибко.

Отличным примером, описывающим наилучшие возможности наблюдаемых, является способ подключения входа фильтра к соответствующему отфильтрованному списку. Когда пользователь вводит символы, список обновляется. Observables обрабатывают соответствующие запросы 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 есть две отличные презентации:

Кристоф Бургдорф также написал несколько отличных постов в блоге на эту тему:

в действии

На самом деле в отношении вашего кода вы смешали два подхода ;-) Вот они:

  • Управляйте наблюдаемым самостоятельно . В этом случае вы обязаны вызвать 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();
       }
    }
    

    Возвраты от обоих методов getи mapметодов являются наблюдаемым, а не результатом (так же, как с обещаниями).

  • Позвольте управлять наблюдаемым по угловому шаблону . Вы также можете использовать 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());
       }
    }
    

Вы можете заметить, что наблюдаемые являются ленивыми. Таким образом, соответствующий HTTP-запрос будет вызван только один раз, когда прослушиватель подключен к нему, используя subscribeметод.

Вы также можете заметить, что mapметод используется для извлечения содержимого JSON из ответа и использования его затем в наблюдаемой обработке.

Надеюсь, это поможет тебе, Тьерри


Спасибо за все ссылки. Но можешь ли ты помочь мне с моей шуткой?
Nyks

Я обновил свой ответ с более подробной информацией о вашем коде. Надеюсь, это поможет вам ;-)
Тьерри Темплиер

извините, что я не смог принять ваш ответ. Это более ясный, но принятый и оцененный ответ помог мне понять достаточно о моем вопросе. Но, надеюсь, вы получите хорошие хиты за четкий ответ, так как у вас есть более подробное объяснение. Принятый ответ тоже для хорошего базового занижения.
micronyks

2
Тьерри Темплиер: это отличный ответ, но одна вещь мне не ясна, я подумал, что http.get ('friends.json') .map (response => response.json ()) возвращает наблюдаемый <Array <Object >>. Если да, то почему вы отправляете это на этот результат? они разные типы.
Став Альфи

@StavAlfi pipes также являются observables. проверьте это видео: youtube.com/watch?v=bVI5gGTEQ_U, предложенный thierry для получения дополнительной информации.
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);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.