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

AsyncPipe

Одним из встроенных классов, который в отличие от других pipes уже по умолчанию представляет тип impure. AsyncPipe позволяет получить результат асинхронной операции.

AsyncPipe отслеживает объекты Observable и Promise и возвращает полученное из этих объектов значение. При получении значения AsyncPipe сигнализирует компоненту о том, что надо проверить изменения. Если компонент уничтожается, то AsyncPipe автоматически отписывается от объектов Observable и Promise, что предотвращает возможные утечки памяти.

Используем AsyncPipe:

 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
28
29
30
31
32
33
import { Component } from '@angular/core';
import { Observable, interval } from 'rxjs';
import { map } from 'rxjs/operators';

@Component({
    selector: 'my-app',
    template: `
        <p>Модель: {{ phone | async }}</p>
        <button (click)="showPhones()">
            Посмотреть модели
        </button>
    `,
})
export class AppComponent {
    phones = [
        'iPhone 7',
        'LG G 5',
        'Honor 9',
        'Idol S4',
        'Nexus 6P',
    ];

    phone: Observable<string>;
    constructor() {
        this.showPhones();
    }

    showPhones() {
        this.phone = interval(500).pipe(
            map((i: number) => this.phones[i])
        );
    }
}

Здесь с периодичностью в 500 миллисекунд в шаблон компонента передается очередной элемент из массива phones.

Скриншот

Компонент не должен подписываться на асинхронное получение данных, обрабатывать их, а при уничтожении отписываться от получения данных. Всю эту работу делает AsyncPipe.

Поскольку AsyncPipe позволяет легко извлекать данные из результата асинхронных операций, то его очень удобно применять, например, при загрузке данных из сети. Для примера определим следующий проект:

Структура

В файле http.service.ts определим сервис, который получает данные с сервера:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

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

    getUsers() {
        return this.http.get('users.json');
    }
}

Для хранения данных в корневой папке проекта определим файл users.json:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[
    {
        "name": "Bob",
        "age": 28
    },
    {
        "name": "Tom",
        "age": 45
    },
    {
        "name": "Alice",
        "age": 32
    }
]

В файле app.component.ts использует сервис:

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

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

Опять же загрузка данных запускается в методе ngOnInit(). В шаблоне компонента к полученным данным применяется AsyncPipe:

1
<li *ngFor="let user of users | async"></li>

И когда данные будут получены, то они сразу будут отображены на веб-странице:

Скриншот

Ну чтобы загрузка данных из сети сработала, надо добавить в AppModule модуль HttpClientModule:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';

import { HttpClientModule } from '@angular/common/http';
@NgModule({
    imports: [BrowserModule, HttpClientModule],
    declarations: [AppComponent],
    bootstrap: [AppComponent],
})
export class AppModule {}

Комментарии