Код RxJS включает подписку на наблюдаемые объекты. Множество подписок.

Если каждой подписке назначена собственная переменная или свойство, управлять ситуацией может быть сложно.

К счастью, есть методы, такие как использование takeUntil или takeWhile, которые значительно упрощают работу с подписками. Если вы не знакомы с этими методами, прочтите Не отказываться от подписки.

Однако бывают ситуации, когда вам все же нужно иметь дело с подписками. Например, иногда бывает необходимо управлять подписками при написании операторов.

Давайте посмотрим на подписки и то, как состав подписки можно использовать для упрощения некоторых операторов пользовательской зоны.

Что такое подписка?

Класс Subscription и связанные с ним типы выглядят так:

Экземпляр Subscription - это то, что возвращается при вызове subscribe, и в большинстве случаев вызывается только unsubscribe метод подписки. Однако класс Subscription также имеет методы add и remove.

Метод add можно использовать для добавления дочерней подписки или функции удаления к родительской подписке. Когда родительская подписка отменяется, все дочерние подписки, которые были добавлены к ней, также отменяются.

Метод remove удаляет дочернюю подписку из родительской - то, что вам вряд ли понадобится при составлении подписок. Однако у этого метода есть цель: когда дочерний элемент отказывается от подписки, он удаляется от своего родителя.

Давайте посмотрим, как add можно использовать для упрощения оператора земли пользователя.

Добавление подписок

Вот реализация конвейерного оператора, который я называю subsequent:

Оператор subsequent отражает источник и позволяет первым count уведомлениям проходить без изменений, но применяет указанный operator ко всем последующим уведомлениям.

Он работает, используя publish для получения горячего наблюдаемого, которое отражает источник, а затем использует concat, чтобы гарантировать, что подписки на начальные и последующие наблюдаемые происходят в определенном порядке.

Есть две подписки: одна делается на concatenated наблюдаемый; и еще один делается для published наблюдаемого - через вызов connect.

Возвращенная функция удаления - из функции, переданной в Observable.create - должна вызывать unsubscribe для обеих подписок.

Это можно сделать немного проще, используя состав подписки:

Вместо использования переменной для отслеживания подписки, сделанной на наблюдаемый published, ее можно добавить к подписке, сделанной на наблюдаемый concatenated.

И вместо того, чтобы возвращать функцию удаления, функция, переданная в Observable.create, может возвращать саму подписку. Затем, когда подписчик отписывается от полученного наблюдаемого объекта, для подписки будет вызываться unsubscribe, и подписка на оба объекта concatenated и published будет отменена.

Создание явных подписок

Подписки могут быть составлены с использованием экземпляра Subscription, возвращенного в результате вызова unsubscribe, но они также могут быть составлены с использованием явно созданных подписок.

Вот реализация конвейерного оператора, который я называю prioritize:

Он вызывает selector, передавая две наблюдаемые, которые отражают источник. Однако гарантируется, что первый наблюдаемый объект был подписан на источник первым, поэтому уведомления от первого наблюдаемого будут происходить раньше, чем от второго. Это иногда полезно при составлении наблюдаемых уведомлений, необходимых операторам типа bufferWhen.

В этой реализации есть несколько подписок, и вместо добавления к подписке, возвращаемой вызовом subscribe, реализация создает явный родительский Subscription и добавляет к нему дочерние подписки.

Попался

При составлении подписки следует помнить о том, что порядок отмены подписки может быть важным.

Например, если бы prioritze имела эту более простую реализацию, в ней была бы ошибка:

Здесь возвращенная подписка - это подписка, сделанная, когда субъект prioritized подписан на published наблюдаемый, а не подписка, сделанная на наблюдаемый объект, на который подписан observer.

Введенная ошибка заключается в следующем:

  • Когда источник завершает работу, уведомление о завершении сначала получает prioritized субъект, который затем отписывается.
  • Когда prioritized субъект отменяет подписку, он также отменяет подписку на наблюдаемый объект, возвращаемый selector.
  • Наблюдаемый объект, возвращаемый selector, не получит полного уведомления, поэтому observer также не получит его. Это означает, что полное уведомление от источника не будет отражено.

Как правило, если у вас есть несколько подписок в операторе пользовательской области и вы используете состав подписки, вы должны использовать явный родительский экземпляр Subscription.

Этот пост также опубликован в моем личном блоге: ncjamieson.com.