Это вольный перевод очень хорошей статьи
https://netbasal.com/creating-custom-operators-in-rxjs-32f052d69457
В этом материале вместо слова наблюдаемый (Observable) используется слово издатель, а вместо слова наблюдатель (Observer) - слово подписчик.
Что такое оператор? Это издатель, который принимает на вход другого
издателя. Простейший оператор будет выглядеть так:
function myOperator<T>(source:Observable<T>){
return source;
}
Этот оператор бесполезен, так как возвращает (или передаёт далее по
цепочке) того же издателя, что и получает, но тем не менее это
оператор!
Теперь давайте попробуем вернуть какого-нибудь другого издателя:
function myOperator<T>(source: Observable<T>){
return new Observable(subscriber=>{
subscriber.next(1);
subscriber.complete();
})
}
Этот оператор никак не использует входного издателя, а просто возвращает единицу.
Теперь попробуем создать оператор, который будет отфильтровывать
значения null
и undefined
и не будет пускать их дальше по цепи.
function filterNil() {
return function <T>(sourse: Observable<T>) {
return new Observable(s => {
sourse.subscribe(
{
next: (v) => {
if (v!==undefined&&v!==null) {
s.next(v);
}
},
error: (error) => {
s.error();
},
complete: () => {
s.complete();
}
}
)
})
}
}
Почему мы обернули оператор в ещё одну функцию? Это для того, чтобы было
удобно передавать оператору какие-то аргументы. Теперь эта функция
возвращает оператор и вызов функции равносилен применению оператора.
Но что-то не так - мы только что создали утечку памяти. Каждый
издатель должен возвращать функцию unsubscribe()
, которая выполняет все
необходимые по очистке памяти действия, а издатель в нашем операторе
такую функцию не возвращает. Для того, чтобы всё заработало как надо
добавим ещё одну строку
function filterNil() {
return function <T>(sourse: Observable<T>) {
return new Observable(s => {
sourse.subscribe(
{
next: (v) => {
if (v!==undefined&&v!==null) {
s.next(v);
}
},
error: (error) => {
s.error();
},
complete: () => {
s.complete();
}
}
)
return () => s.unsubscribe(); <===
})
}
}
Конструкция Observable.subscribe()
возвращает объект Subscription
,
поэтому можно сократить код, показанный выше просто возвратив сам объект
подписки. Теперь при вызове unsubscribe()
будет вызываться метод
unsubscribe()
подписки, которую мы возвращаем.
function filterNil() {
return function <T>(sourse: Observable<T>) {
return new Observable(s => {
return sourse.subscribe(
{
next: (v) => {
if (v!==undefined&&v!==null) {
s.next(v);
}
},
error: (error) => {
s.error();
},
complete: () => {
s.complete();
}
}
)
})
}
}
Рекомендуется создавать свои операторы на основе существующих и вот как
будет выглядеть оператор filterNil
, созданный при помощи оператора
filter
function filterNil() {
return function <T>(source: Observable<T>) {
return source.pipe(filter(v=>v!==undefined && v!=null));
}
}
А так как операторы функции блока pipe
сами по себе уже возвращают функции, то
есть оператор filter
уже вернёт нужную нам функцию, принимающую и
возвращающую издателя, то можно сократить код до
function filterNil() {
return filter(v=>v!==undefined&&v!=null);
}
Top comments (0)