RxJS 的 Subject 及其使用场景

阅读时长 8 分钟读完

RxJS 是一个用于处理异步事件的库,Subject 是 RxJS 中非常常用的一个概念,最常被用于事件的发布与订阅中。假设你已经了解了 RxJS 基础的 Observables 和 Operators,那么接下来我们来看一下什么是 RxJS 的 Subject,它有什么作用以及应该如何使用。

Subject 的定义

Subject 是 RxJS 中最基础的概念之一,它是一个特殊类型的 Observable,既可以订阅也可以发送事件,同时也可以作为 Observer 来接收其它 Observable 或 Subject 发射出来的事件。

具体来说,我们可以通过 new Subject() 来创建一个 Subject 实例,它具备以下能力:

  1. 发送事件

Subject 实例可以通过 .next(value) 方法来发送一个值。

  1. 订阅事件

Subject 实例可以通过 .subscribe(callback) 或 .subscribe(observer) 来订阅事件。这与一般的 Observable 并没有什么不同。

  1. 引用计数

当 Subject 实例作为 Observer 来订阅其它 Observable 或 Subject 时,每当被它订阅的 Observable 或 Subject 调用 .complete() 或 .error() 时,Subject 实例就会取消订阅。相当于一个引用计数,当计数为 0 时,Subject 实例也将成为冷 Observable,不再发射值。

使用场景

Subject 为什么这么重要?什么时候应该使用它呢?

发送值类型的事件

Subject 可以作为一个事件总线来使用,当需要发送值类型的事件时,你可以考虑使用 Subject。例如:

这段代码中,Subject 实例可以发送事件,也可以作为事件总线,将一个值类型的事件接受者(即 .subscribe 注册的回调函数)绑定到多个事件源(即 .next 发送事件)。这就大大简化了组件之间的数据交换,并且提高了代码的复用性和可维护性。

充当状态对象

当需要在多个组件中共用一个状态对象时,可以考虑使用 Subject。以下以 Angular 为例:

-- -------------------- ---- -------
------ - ---------- - ---- ----------------
------ - --------------- - ---- -------

-------------
  ----------- -------
--
------ ----- ------------ -
  ------- ------------ - --- ----------------- ----- --- ---- - ---
  ------ - ---------------------------------

  ----------------- ------- ---- ------- -
    ------------------------ ----- --- ---
  -
-

以上代码中,我们使用 BehaviorSubject(继承了 Subject 的行为)来保存状态,使用它的好处是:

  1. 组件在订阅状态时,可以用 | async 管道简化模板代码,同时省去 unsubscribe 操作;

  2. 多次订阅时,始终可以获取到最新的状态,并且可以通过 .next() 方法来更新该状态。

作为组件之间的数据传递机制

当需要在组件之间传递数据时,可以考虑使用 Subject。例如:

-- -------------------- ---- -------
------ - ---------- - ---- ----------------
------ - ------- - ---- -------

-------------
  ----------- -------
--
------ ----- ------------------- -
  ------- -------------- - --- ------------------
  -------- - -----------------------------------

  -------------- -
    ------------------------------------
  -
-

以上代码中,我们创建了一个全局的 NotificationService,以 Subject 作为数据传递机制。组件 A 可以通过 notification() 方法来发送通知,同时组件 B 可以通过订阅 message$ 来接收通知。这种方式可以很方便地解决组件之间的数据传递问题,而且代码结构也很清晰。

代码示例

以下是一个使用 Subject 实现组件之间的通信的示例代码:

-- -------------------- ---- -------
------ - --------- - ---- ----------------
------ - -------------- - ---- --------------------

------------
  --------- -------------
  --------- -
    ------------- ------
    ------ --------- ----------- --

    ------- ---------------------------------------------------
  --
--
------ ----- --------------- -
  ------------------- --------------- --------------- --

  -------------------- ------- -
    -----------------------------------------
  -
-

------------
  --------- ------------
  --------- -
    ------------- ------
    ----- ------- ------
  --
--
------ ----- -------------- -
  -------- -------

  ------------------- --------------- --------------- --

  ---------- -
    -------------------------------------------------- -- -
      ------------ - --------
    ---
  -
-

-------------
  ----------- -------
--
------ ----- -------------- -
  ------- ------- - --- ------------------

  -------------------- ------- -
    ---------------------------
  -

  ------------ -
    ------ ----------------------------
  -
-

以上代码中,我们定义了 ParentComponent 和 ChildComponent 两个组件,它们之间通过 SubjectService 来传递消息。在 ParentComponent 中,我们通过 sendMessage() 方法来发送消息;在 ChildComponent 中,我们通过 getMessage() 方法来订阅消息,当有新的消息时,则会将该消息渲染到模板中。最后,我们将 SubjectService 定义为可注入的服务,以便在多个组件中重复使用。

总结

Subject 是 RxJS 中非常重要的概念之一,它同时具有 Observable 和 Observer 的能力,可以作为数据总线、状态对象、数据传递机制等多种用途。在实际的开发中,有时会遇到多个组件之间需要共享状态或传递数据的情况,这时使用 Subject 会是一种非常方便的解决方案。当然了,需要注意的是,在使用 Subject 时也要注意避免内存泄漏等问题。如果你还没有使用过 RxJS 中的 Subject,可以参照本文中的示例代码尝试一下。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64abcf3348841e98947a68bb

纠错
反馈