RxJS 操作及其在 Angular 应用中的实践

阅读时长 12 分钟读完

RxJS 是一个让开发者能够方便地处理异步的 JavaScript 库。通过 RxJS,我们可以使用响应式编程的思想,将所有异步操作都当作流来处理,使得我们的代码更加简洁、易于维护。本文将深入介绍 RxJS 的操作以及在 Angular 应用中的实践,内容详细、有深度、学习和指导意义,读者可以在阅读本文后获得深入理解和使用 RxJS 的能力。

Observable 和 Subscriber

在 RxJS 中,最核心的概念是 Observable 和 Subscriber。Observable 表示一个数据流,可以是一个事件、一个 HTTP 请求的响应,甚至可以是用户输入的一次键盘敲击;而 Subscriber 则表示对这个数据流的订阅。在 RxJS 中,我们可以使用一些操作符(Operators)来对数据流进行操作,例如对流进行过滤、转换、组合等等。

在 Angular 中,我们通常会使用 HttpClient 来进行 HTTP 请求。然而,HttpClient 所返回的值并不是一个简单的值,而是一个 Observable。因此,我们需要对返回的 Observable 进行订阅操作,以获取我们需要的数据。

下面是一个简单的实例,当用户在输入框中输入文字时,会根据这个文字去请求后台数据,并将请求结果展示在页面上:

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

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

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

在上面的代码中,我们将用户输入的文字作为参数传递给 search() 函数,这个函数会返回一个 Observable,通过使用 debounceTime() 操作符来延迟请求并防止用户频繁请求。distinctUntilChanged() 操作符会确保只有在查询参数变化时才会发起请求。switchMap() 操作符会处理返回的 Observable,将其转化为我们需要的结果。

操作符

RxJS 提供了大量的操作符,我们可以使用这些操作符对 Observable 进行转换、过滤、组合等等操作。下面就介绍其中一些常用的操作符。

map()

map() 操作符会将 Observable 中的每个值,使用传入的函数进行转换,返回一个新的 Observable。例如:

可以看到,map() 操作符将原来的 Observable 中的每个数都乘以 2,最后返回一个乘以 2 的新的 Observable。

filter()

filter() 操作符会从一个 Observable 中过滤出符合条件的值,返回一个新的 Observable。例如:

可以看到,filter() 操作符将原来的 Observable 中所有的奇数过滤掉,实现了只输出偶数的目的。

debounceTime()

debounceTime() 操作符会等待一段时间,如果 Observable 在这段时间内没有新的值被发射出来,就会将这个值发射出去。这个操作符常常用来防止用户操作过于频繁,例如搜索框的联想功能可以使用 debounceTime()。例如:

上面的代码会在用户输入完成后,等待 1 秒才会输出“用户输入完成”。

switchMap()

switchMap() 操作符用来处理 Observable,它可将 Observable 转化为返回另一个 Observable 的函数。例如:

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

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

上面的代码中,outerObservable 作为一个外部 Observable,内部订阅了一个 innerObservable。当 outerObservable 中有新的值被发射后,switchMap() 会取消以前订阅的内部 Observable 并订阅新的内部 Observable,最终输出的是 innerObservable 中的所有值。

tap()

tap() 操作符用来查看 Observable 中的值但不影响值的传递,它对于调试代码很有用。例如:

上面的代码中,tap() 操作符不会进行任何操作,仅仅将 Observable 中的每个值输出到控制台上。

实践

下面是一些在 Angular 应用中实践 RxJS 的例子。

处理 HTTP 请求

在 Angular 中,我们一般使用 HttpClient 对 HTTP 请求进行处理。HttpClient 所返回的是一个 Observable,我们可以使用 map()、catchError() 等操作符对其进行操作。例如:

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

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

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

上面的代码中,我们通过 ApiService 发起一个 HTTP 请求,将返回的 Observable 通过 map() 操作符处理过后返回给组件使用。如果请求出错,则会调用 catchError(),在这里我们可以对错误进行处理后返回。

处理 Route

在 Angular 中,我们可以使用 Router 对路由进行处理。Router 所返回的值也是一个 Observable,我们可以使用许多操作符对其进行处理。例如:

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

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

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

上面的代码中,我们在组件初始化时对 ActivatedRoute 进行订阅,获得路由参数,并使用 map() 操作符将参数转化为我们需要的值后输出。由于路由参数是一个 Observable(当用户在同一页面间导航时),因此我们必须使用订阅,而不是直接获取参数。

处理输入框

在 Angular 中,我们可以使用双向绑定将用户输入的值与组件中的属性绑定在一起。RxJS 使得我们可以对用户输入进行进一步的处理,例如使用 debounceTime() 操作符来防止用户频繁地发起请求。例如:

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

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

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

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

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

上面的代码中,我们首先在组件初始化时初始化 results 和 searchTerm,并通过订阅 search() 函数将搜索框的默认值传递到搜索函数中。当用户输入框发生改变时,会调用 handleSearch() 函数,使用 debounceTime()、distinctUntilChanged() 等操作符对用户输入的值进行处理,并使用 switchMap() 操作符将输入的值转化成一个 Observable,并将这个 Observable 传递给订阅函数。

总结

RxJS 是一个非常强大的库,能够方便处理异步操作。在 Angular 中使用 RxJS,我们可以轻松地处理 HTTP 请求、路由和用户输入等操作。本文详细介绍了 RxJS 的操作符和在 Angular 应用中的实践,希望读者通过本文的学习,能够获得深入理解和使用 RxJS 的能力。

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

纠错
反馈