Перейти к содержанию

Объект Observable и библиотека RxJS

Методы класса HttpClient после выполнения запроса возвращают объект Observable<any>, который определен в библиотеке RxJS ("Reactive Extensions"). Она не является непосредственно частью Angular, однако широко используется особенно при взаимодействии с сервером по http. Эта библиотека реализует паттерн "асинхронный наблюдатель" (asynchronous observable). Так, выполнение запроса к серверу с помощью класса HttpClient выполняются в асинхронном режиме.

Естественно чтобы задействовать функционал RxJS в приложении, в проект должна быть добавлена соответствующая зависимость rxjs:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  "name": "helloapp",
  "version": "1.0.0",
  "description": "First Angular 7 Project",
  "author": "Eugene Popov <metanit.com>",
  "scripts": {
    "dev": "webpack-dev-server --hot --open",
    "build": "webpack"
  },
  "dependencies": {
    "rxjs": "^6.3.3"
    // остальное содержимое секции
  },
  "devDependencies": {
    // содержимое секции
  }
}

Используя специальные методы для объекта Observable, например, map и filter, можно произвести некоторую постобработку полученных от сервера результатов.

Так, возьмем проект из прошлой темы:

Структура приложения

Например, определим в файле users.json данные, которые напрямую не соответствуют массиву объектов User:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  "userList": [
    {
      "userName": "Bob",
      "userAge": 28
    },
    {
      "userName": "Tom",
      "userAge": 45
    },
    {
      "userName": "Alice",
      "userAge": 32
    }
  ]
}

В качестве модели данных используем класс User:

1
2
3
4
export class User {
  name: string
  age: number
}

Определим следующий код сервиса, который будет получать данные из users.json:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import { Injectable } from '@angular/core'
import { HttpClient } from '@angular/common/http'
import { User } from './user'
import { Observable } from 'rxjs'
import { map } from 'rxjs/operators'

@Injectable()
export class HttpService {
  constructor(private http: HttpClient) {}

  getUsers(): Observable<User[]> {
    return this.http.get('users.json').pipe(
      map((data) => {
        let usersList = data['userList']
        return usersList.map(function (user: any) {
          return { name: user.userName, age: user.userAge }
        })
      })
    )
  }
}

Смысл использования специального сервиса для работы с http заключается в сокрытии деталей отправки запросов. Компонент же ожидает получить какие-то конкретные данные, например, в виде набора объектов User. С помощью метода map библиотеки rxjs можно преобразовать данные из одного формата в другой.

У результата метода get() мы можем вызвать метод pipe(), который позволяет обработать результаты запроса. Для этого метод pipe в качестве первого параметра принимает функцию обработки данных запроса. В данном случае в роли такой функции выступает оператор map, который преобразует результаты запроса в новые объекты.

Но чтобы использовать элементы библиотеки RxJS, их надо импортировать:

1
2
import { Observable } from 'rxjs'
import { map } from 'rxjs/operators'

В итоге весь метод getUsers() возвращает объект Observable<User[]>.

Теперь используем сервис в классе компонента:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { Component, OnInit } from '@angular/core'
import { HttpService } from './http.service'
import { User } from './user'

@Component({
  selector: 'my-app',
  template: `
    <ul>
      <li *ngFor="let user of users">
        <p>Имя пользователя: {{ user?.name }}</p>
        <p>Возраст пользователя: {{ user?.age }}</p>
      </li>
    </ul>
  `,
  providers: [HttpService],
})
export class AppComponent implements OnInit {
  users: User[] = []

  constructor(private httpService: HttpService) {}

  ngOnInit() {
    this.httpService
      .getUsers()
      .subscribe((data) => (this.users = data))
  }
}

Комментарии