Как работает оператор from в RxJS
Development | Комментировать запись
Оператор RxJS from используется для преобразования итерируемых данных в наблюдаемые объекты. Это свойство может быть особенно полезно, если вы хотите превратить типы передаваемых и совместно используемых данных в наблюдаемые последовательности или же если функция собирается получить наблюдаемый объект и воздействовать на него. Также оператор from можно использовать, если вам нужно применить оператор RxJS, который обычно недоступен для исходного типа данных.
К итерируемым типам, которые можно преобразовать в наблюдаемые объекты с помощью from, относятся массивы, карты, наборы, промисы, узлы DOM и функции-генераторы. Ниже мы рассмотрим примеры некоторых из этих типов.
Массивы и оператор from
Чаще всего оператор from используется для преобразования массива в наблюдаемый объект:
let myArr = ['🐦', '😺', '🐕', '🐊'];
Rx.Observable
.from(myArr)
.filter(x => x !== '🐦')
.map(x => `Hello ${x}!`)
.subscribe(console.log);
// Hello 😺!
// Hello 🐕!
// Hello 🐊!
Синхронные и асинхронные наблюдаемые объекты
По умолчанию оператор from возвращает синхронные наблюдаемые объекты:
let myArr = ['😺', '🐕', '🐊'];
console.log('Before');
Rx.Observable
.from(myArr)
.map(x => `Hello ${x}!`)
.subscribe(console.log);
console.log('After');
// Before
// Hello 😺!
// Hello 🐕!
// Hello 🐊!
// After
Однако при необходимости их можно сделать асинхронными при помощи Rx.Scheduler.async:
let myArr = ['😺', '🐕', '🐊'];
console.log('Before');
Rx.Observable
.from(myArr, Rx.Scheduler.async)
.map(x => `Hello ${x}!`)
.subscribe(console.log);
console.log('After');
// Before
// After
// Hello 😺!
// Hello 🐕!
// Hello 🐊!
Функции-генераторы и оператор from
Читайте также: Функции-генераторы в JavaScript ES6/ES2015
Функции-генераторы относятся к итерируемым типам данных, потому их легко можно преобразовать в наблюдаемый объект при помощи оператора from:
function* generateUnique() {
let num = 0;
while (true) {
yield num++;
}
}
Rx.Observable.from(generateUnique())
.take(3)
.subscribe(console.log);
// 0
// 1
// 2
Примечание: Здесь мы используем оператор take для завершения наблюдаемого объекта после указанного количества значений. В противном случае у нас получился бы бесконечный наблюдаемый объект и при подписке случилась бы ошибка.
А вот немного более сложный пример, в котором также используется оператор zip (для объединения значений нескольких наблюдаемых объектов):
function* generateName() {
yield 'Cat';
yield 'Dog';
yield 'Bird';
return;
}
function* generateEmoji() {
yield '😺';
yield '🐕';
yield '🐦';
return;
}
function* generateSound() {
yield 'Meow';
yield 'Woof';
yield 'Tweet';
return;
}
const names = Rx.Observable.from(generateName());
const emojis = Rx.Observable.from(generateEmoji());
const sounds = Rx.Observable.from(generateSound());
const combined = Rx.Observable.zip(names, emojis, sounds, (name, emoji, sound) => {
return `The ${name} ${emoji} goes ${sound.toUpperCase()}`;
})
.subscribe(console.log);
// The Cat 😺 goes MEOW
// The Dog 🐕 goes WOOF
// The Bird 🐦 goes TWEET
Примечание: Обратите внимание, что здесь для объединения генераторов и наблюдаемых объектов также используется оператор spawn, но в настоящее время в RxJS 5+ этот оператор недоступен.
Промисы и оператор from
Промисы также можно легко преобразовать в асинхронные наблюдаемые объекты, которые будут обертывать значения resolve или reject:
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello');
}, 2000);
});
Rx.Observable
.from(myPromise)
.subscribe(x => console.log(x, ' World!'));
// Hello World! (after 2 seconds)
Узлы DOM
Давайте посмотрим на следующий простой пример, в котором набор из 3 узлов DOM преобразуется в наблюдаемый объект и сопоставляется для извлечения только textContent:
<h2>Hey,</h2>
<h2>Hello</h2>
<h2>Alligator!</h2>
<script>
const h2s = document.querySelectorAll('h2');
Rx.Observable.from(h2s)
.map(h2 => h2.textContent)
.subscribe(console.log);
// Hey,
// Hello
// Alligator!
</script>
Кратко о строках
Строки тоже можно итерировать, следовательно, с ними можно использовать оператор from, но при этом каждый символ в строке будет отдельным значением:
Rx.Observable
.from('Hi!')
.subscribe(console.log);
// H
// i
// !
Если вы хотите преобразовать строку в единое значение, вам нужно использовать оператор of, а не from:
Rx.Observable
.of('Hi!')
.subscribe(console.log);
// Hi!
Tags: RxJS