26 KiB
title | localeTitle |
---|---|
Reactive Extensions | Реактивные расширения |
Реактивные расширения в угловом
мотивация
Реактивные расширения для JavaScript (RxJS) - это библиотека для наблюдаемых потоков данных. RxJS устанавливает с помощью Angular при выполнении командной строки ng new [name-of-application]
. Это использует интерфейс командной строки с угловым интерфейсом (CLI). RxJS дополняет процесс упорядочения данных через Observable
. Объект Observable
облегчает поток итерируемых данных.
Потоки данных не являются основным прецедентом. В конце концов, поток данных передает параллельные потоки событий. События выдают, поэтому приложение знает, когда поступают данные. Хотя потоки событий формируют ядро того, что добавляет RxJS, эта статья также относится к ним как к потокам данных.
Потоки выполняются либо синхронно (немедленно), либо асинхронно (сверхурочно). RxJS легко справляется с обоими случаями через поток данных Observable
. Тем не менее строгая асинхронность. Работа с встроенной памятью, повторяющиеся данные происходят немедленно, в то время как для получения внешних данных требуется время. Угловая поддержка библиотеки RxJS, так что она может обрабатывать оба варианта использования с потоками данных.
Реактивное программирование
Прежде чем погрузиться в воду, важно понять парадигму, поддерживающую библиотеку RxJS. Как уже упоминалось, он работает через объект Observable
который оптимизирует данные, генерирующие события.
Функции RxJS вокруг базы Observable
. Вся его библиотека дополняет то, что она может сделать. RxJS включает и другие объекты, включая Subject
, Subscription
и Observer
. Каждый из них является собственным вариантом базы Observable
.
RxJS возникла из парадигмы реактивного программирования. Эта парадигма ввела наблюдаемую картину. В ней существует эта ключевая идея: один Observable
излучает в то время как все его Observer
s получить уведомление. Observer
подписываются на Observable
чтобы получать уведомление. Это уведомление может означать несколько вещей.
Это может означать изменение данных или прибытие данных, как это обычно указывается в этой статье. Он может сигнализировать об изменении какой-либо части приложения, которая влияет на Observer
s.
Эта наблюдаемая модель также стремится отделить понятия. Observable
должен функционировать без каких-либо Observer
и наоборот. Обычно это означает, что они могут стоять автономно, а не полностью функционировать без друг друга.
Если вам интересно, вы можете узнать больше об основах реактивного программирования, прочитав эту статью в Википедии . В этом разделе рассказывается о том, что необходимо для остальной части статьи.
Наблюдаемые
Для того, чтобы быстро повторить, Observable
можно наблюдать с. Это позволяет Observable
обеспечивать обратную связь с зависимостями на основе потока данных. В RxJS Observable
- это собственная фабричная функция, используемая для создания объектов Observable
. Их основной план состоит в следующем.
import { Observable } from 'rxjs';
const observable = Observable.create((source) => {
source.next(data);
});
.next
передает данные при передаче события своим наблюдателям. An Observable
эмитирует данные внутри своего .create
обратного вызова с помощью .next
. Он принимает один аргумент, представляющий данные для испускания. Observable
еще не был внедрен в JavaScript. RxJS обеспечивает замену из своей библиотеки.
Следующий шаг - наблюдатели. Чтобы сообщить функции или объекту наблюдать Observable
, используется следующий синтаксис: observable.subscribe(observer)
. Другой способ взглянуть на это - producer.subscribe(consumer)
. Наблюдаемые производят данные, вызывая .next
. Затем потребители уведомляются при получении данных.
import { Observable } from 'rxjs';
const observable = Observable.create((source) => {
source.next("Hello");
source.next("World!");
});
observable.subscribe((word) => console.log(word));
// console output
/*
Hello
World!
*/
Два вызова .next
происходят из обратного вызова Observable
.create
(производитель данных). Это приводит к двум отдельным выходам консоли от наблюдателя (потребителя данных).
Два вызова .next
представляют собой синхронный поток данных. Потоки концептуализируют данные как линейный поток в порядке. Он либо решает синхронно, либо асинхронно, в зависимости от доступности данных.
Если данные, содержащие поток, легко доступны, он выполняется синхронно. В противном случае поток решает асинхронно сверхурочно. Порядок данных в любом случае всегда один и тот же в зависимости от вызова .next
пределах наблюдаемого.
Observable
работает как очередь. Вызов .next
на кусок данных подталкивает его к задней части очереди. После этого данные появляются с фронта.
Observable
потоки данных имеют огромное значение. Они детерминированы в своем порядке и разумно зависят от доступности данных. Кроме того, любое количество наблюдателей может наблюдать за источником данных Observable
. Это означает, что данные могут производить один раз и выделять все в одной операции.
Функции обратного вызова - это не единственный способ использования данных. Наблюдатели могут цеплять друг в друга как производители и потребители.
const observableI = Observable.create((source) => {
source.next("Hello World!");
});
const observableII = new Observable().subscribe((v) => console.log(v));
observableI.subscribe(observableII);
// console output
/*
Hello World!
*/
.subscribe
находится в объекте Observable
. Вы можете назвать его Observable
как его источник (продюсер), а другой - как аргумент (потребитель). Данные могут проходить (излучать) через любое количество наблюдаемых.
Реактивные расширения для JavaScript (RxJS)
Потоковые данные хороши, но какова точка, если наблюдаемые не могут редактировать поток? Это где библиотека RxJS вступает в игру. Он предоставляет операторам, которые выполняют различные мутации в потоке данных.
Угловые рычаги используют эти операторы для преобразования входящих данных. Разработчики могут обрезать любые ненужные данные из входящего потока с использованием операторов RxJS. Это экономит память и устраняет необходимость в дополнительной логике преобразования.
RxJS предлагает отклонения от стандартного Observable
например Subject
, Subscription
и Observer
. Подумайте об этих отклонениях как о специальных ароматах традиционного Observable
. Они не нужны, чтобы использовать библиотеку. Тем не менее, варианты, подобные Subject
имеют невероятные прецеденты, превосходящие стандарт Observable
.
Эта статья придерживается стандартного Observable
. Все операторы потока данных из RxJS работают через Observable
.
Многие операторы ядра RxJS были созданы из массивов JavaScript. Прототип объекта Array содержит много параллелей с библиотекой RxJS. Они иначе известны как «Дополнительно». Массивы представляют собой потоковые структуры, подобные наблюдаемым парам данных.
Чтобы лучше понять операторы RxJS, в этой статье мы кратко рассмотрим расширения массива JavaScript. Каждый из функций почти идентичен своему RxJS-аналогу. Разница - это просто формат данных (итерируемый массив против итеративного потока).
Дополнительно
Массивы содержат множество полезных методов. Эти методы называются Extray Array. Все они существуют на прототипе объекта Array. В приведенном ниже списке содержится пять дополнений с параллелями RxJS.
.reduce
.filter
.map
.every
.forEach
Для каждого примера массив выполняет итерацию над собой для получения конечного результата.
.reduce
минимизирует массив в одно значение. .filter
массив с булевой оценкой. .map
преобразует массив по элементам. .every
оценивает true или false для всего массива в зависимости от логического условия. .forEach
выполняет .forEach
через элементы массива.
Массирует потоки модели. Они находятся в порядке друг друга и повторяются один за другим. Наблюдает обтекание элементов данных своим наблюдателям аналогичным образом. Вот почему RxJS включает логическую копию каждого массива в своей библиотеке. Конечно, RxJS предоставляет больше возможностей своим операторам, чем Array Extras.
Основные операторы RxJS
Существует буквально целая библиотека для операторов RxJS. В этой статье рассматриваются те, которые перечислены ниже, которые вдохновили Extreme Array.
.reduce
.filter
.map
.every
.forEach
Ничего не изменилось из предыдущего списка. Ваше понимание Extray Array относится к операторам RxJS. Единственный улов для этого - это функция, называемая .pipe
которая увидит много пользы в следующих нескольких примерах. .pipe
цепи RxJS операторов вместе. Результаты предыдущего оператора переходят в следующий раунд до конечного оператора. Полученные данные затем исходят из наблюдаемого потока.
Обратите внимание на стандартный пример ниже. Используйте его для сравнения для воздействия каждого оператора на испускаемый поток данных.
import { Observable, from } from 'rxjs';
const stream: number[] = [1, 2, 3, 4, 5];
const observable: Observable<number> = from(stream);
observable.subscribe((val: number) => console.log(val));
// console output
/*
1
2
3
4
5
*/
.from
преобразует массив в объект Observable
который вызывает .next
для каждого элемента массива. Функция .pipe
принимает любое количество аргументов в качестве операторов массива. Здесь каждый оператор реализуется. Операторы выполняют на упорядоченных данных в порядке их реализации в качестве аргументов для .pipe
.
уменьшить
.reduce
минимизирует поток данных в одно значение перед испусканием.
import { reduce } from 'rxjs/operators';
const stream: number[] = [1, 2, 3, 4, 5];
const observable: Observable<number> = from(stream).pipe(
reduce((accum, val) => (accum + val))
);
observable.subscribe((val: number) => console.log(val));
// console output
/*
15
*/
Фильтр
.filter
обрезает поток, исключая значения потока, которые не удовлетворяют его условиям.
import { filter } from 'rxjs/operators';
const stream: number[] = [1, 2, 3, 4, 5];
const observable: Observable<number> = from(stream).pipe(
filter((val) => (val % 2 === 0)) // filters out odd numbers
);
observable.subscribe((val: number) => console.log(val));
// console output
/*
2
4
*/
карта
.map
и преобразует каждое текущее значение потока.
const stream: number[] = [1, 2, 3, 4, 5];
const observable: Observable<number> = from(stream).pipe(
map((val) => (val + 1))
);
observable.subscribe((val: number) => console.log(val));
// console output
/*
2
3
4
5
6
*/
Задача: Every и ForEach
Со знанием .every
и .forEach
как Array Extras, попробуйте реализовать их как операторов RxJS. Не стесняйтесь использовать предыдущие примеры для руководства. Немного практики проходит долгий путь после многих чтений!
HTTP в угловом
Этот раздел объединяет RxJS и Angular, чтобы показать, как они взаимодействуют. Как правило, услуга, предоставляемая Angular, обеспечит Observable
. Поток данных Observable
может затем мутировать с использованием операторов .pipe
с .pipe
.
Угловой предоставляет услугу HttpClient
через @angular/common/http
HttpClient
@angular/common/http
. HttpClientModule
также из @angular/common/http
и экспортирует службу HttpClient
. Корневой модуль приложения должен импортировать HttpClientModule
. Это делает HttpClientModule
инъекционным в любом месте приложения.
Служба HttpClientModule
HTTP-запросы. Эти запросы являются асинхронными. Что делает их интересными для Angular, так это то, как обрабатывается запрос. Observable
возвращается с каждым запросом. RxJS может убрать его оттуда.
В следующем примере используется открытый API, созданный Typicode . API предоставляет массив из 100 элементов на асинхронный GET
.
// ./models/post.model.ts
export interface Post {
userId: number;
id: number;
title: string;
body: string;
}
// ./services/json.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, from } from 'rxjs';
import { switchMap, map, filter, reduce } from 'rxjs/operators';
import { Post } from '../models/post.model';
@Injectable({
providedIn: 'root'
})
export class JsonService {
constructor(private http: HttpClient) { }
getPostsByUserId(id: number): Observable<any> {
const trim$ = (stream) => from(stream)
.pipe(
filter((post: Post) => +post.userId === +id),
map((post: Post) => ({ title: post.title, body: post.body })),
reduce((accum: Post[], post: Post) => accum.concat([post]), [])
);
return this.http.get("https://jsonplaceholder.typicode.com/posts")
.pipe(
switchMap((value) => trim$(value))
);
}
}
// ./components/example/example.component.ts
import { Component } from '@angular/core';
import { JsonService } from '../../services/json.service';
import { Post } from '../../models/post.model';
@Component({
selector: 'app-example',
template: `
<h1>Request User Posts</h1>
<span>User: </span><input #userInput>
<button (click)="requestForPosts(userInput.value)">REQUEST</button>
<hr>
<ul>
<div *ngIf="userPosts">
<div *ngFor="let post of userPosts">
<h3>{{ post.title }}</h3>
<p>{{ post.body }}</p>
</div>
</div>
<h3 *ngIf="!userPosts">No posts shown...</h3>
</ul>
`
})
export class ExampleComponent {
userPosts: Post[];
constructor(private json: JsonService) { }
requestForPosts(id: number): void {
this.json.getPostsByUserId(id)
.subscribe((posts: Post[]) => { this.userPosts = posts.length > 0 ? posts : null; });
}
}
json.service.ts
создает Observable
от имени component.example.ts
. Компонент может подписаться на возвращаемый Observable
. Только одно значение излучает к тому времени, когда Observable
разрешает поток данных.
Запрос jsonplaceholder.typicode.com
дает один массив из 100 сообщений. Запрос через HttpClient
дает Observable
. Оператор switchMap
возвращает другое Observable
которое перезаписывает текущий поток. Переменная trim$
хранит Observable
как ее значение. Добавление $
к переменной, используемой для хранения Observable
s, является условным.
from
конвертирует массив из jsonplaceholder.typicode.com
в 100-значение, излучающее Observable
. Затем операторы RxJS просеивают каждую часть данных в потоке. Они удаляют значения потока, не относящиеся к запросу. Обрезка данных происходит таким образом, что значения потока остаются ненужными. Окончательные результаты снова объединяются в единый массив, который испускает его наблюдателям.
В component.example.ts
JsonService ссылается на метод, возвращающий только что описанный Observable
. Этот метод вызывается при нажатии кнопки в шаблоне компонента. Поле ввода также в шаблоне предоставляет один аргумент id
.
При нажатии кнопки JsonService возвращает Observable
который испускает один массив. .subscribe
вызывает на возвращаемом Observable
. Затем компонент устанавливает значение userPosts
равным испускаемому массиву.
Обнаружение углового изменения фиксирует изменение данных класса. Обновления шаблона и *ngFor
обеспечивают, чтобы каждый элемент массива из userPosts
отображал свой собственный элемент шаблона.
Вывод
RxJS обеспечивает ядро Observable
вместе со своими операторами. Библиотека автоматически устанавливается из командной строки с помощью ng new [name-of-app]
(Угловая CLI). Типы и операторы ядра RxJS загружаются соответственно в rxjs
и rxjs/operators
.
Даже если вы не используете CLI, такие сервисы, как HttpClient
, все еще пригодны для использования. Служба возвращает Promise
вместо Observable
если RxJS недоступен. Объект Promise
является родным для JavaScript в отличие от Observable
. Вероятно, это изменится в следующем официальном выпуске JavaScript.
Тем не менее, в полной мере используйте RxJS! Любая итеративная структура может вместить Observable
. С его помощью вся библиотека RxJS становится пригодной для использования. Его операторы эффективно преобразуют данные из потока в результаты. Кроме того, наблюдатели могут подписаться на результаты, увеличивая общую переносимость данных.
источники
- Угловая команда. «Библиотека RxJS». Google . Доступ к 5 июня 2018 года.
- Форбс, Эллиот. «Создание приложения реального времени с помощью Angular и Socket.io Tutorial». TutorialEdge.net , 10 января 2017. Доступен 5 июня 2018 года.
- Команда RxJS. «Документация RxJS». RxJS . Доступ к 5 июня 2018 года.
- Сукале, Райан. «Разница между субъектом Rxjs и наблюдаемым». TutorialHorizon , 23 марта 2017. Доступен 5 июня 2018 года.
- Сообщество Википедии. «Реактивное программирование». Википедия , 2 июня 2018. Доступен 5 июня 2018 года.