Это вольный перевод очень хорошей статьи
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)