點燈坊

失くすものさえない今が強くなるチャンスよ

使用 map() 由 Observable 建立其他 Observable

Sam Xiao's Avatar 2020-06-26

除了可以由 RxJS 的 Operator 建立 Observable 外,我們也可使用 map() 從既有 Observable 繼續建立新 Observable。

Version

macOS Catalina 10.15.4
WebStorm 2020.1
Vue 2.6.11
RxJS 6.5.5

Browser

create000

由一個 Observable 再分別建立兩個 Observable 顯示。

subscriptions()

<template>
  <div>
    <h1>{{ interval1$ }}</h1>
    <h1>{{ interval2$ }}</h1>
  </div>
</template>

<script>
import { interval } from 'rxjs'
import { map } from 'rxjs/operators'

let subscriptions = _ => {
  let interval$ = interval(1000)
  let interval1$ = interval$.pipe(map(x => x * 2))
  let interval2$ = interval$.pipe(map(x => x * 3))

  return { interval1$, interval2$ }
}

export default {
  name: 'app',
  subscriptions,
}
</script>

13 行

let interval$ = interval(1000)
let interval1$ = interval$.pipe(map(x => x * 2))
let interval2$ = interval$.pipe(map(x => x * 3))

由於 subscriptions 本質是 function,因此我們可以在 subscriptions() 直接建立 interval$ observable,除此之外,還可以由 map() 建立新的 Observable。

map()
由 Observable 根據傳入 function 運算成新 Observable

map001

Point-free

<template>
  <div>
    <h1>{{ interval1$ }}</h1>
    <h1>{{ interval2$ }}</h1>
  </div>
</template>

<script>
import { interval } from 'rxjs'
import { map } from 'rxjs/operators'
import { multiply } from 'ramda'

let subscriptions = _ => {
  let interval$ = interval(1000)
  let interval1$ = interval$.pipe(map(multiply(2)))
  let interval2$ = interval$.pipe(map(multiply(3)))

  return { interval1$, interval2$ }
}

export default {
  name: 'app',
  subscriptions,
}
</script>

15 行

let interval1$ = interval$.pipe(map(multiply(2)))
let interval2$ = interval$.pipe(map(multiply(3)))

map() 的 callback 可進一步使用 Ramda 的 multiply() 加以 point-free。

Function Composition

<template>
  <div>
    <h1>{{ interval1$ }}</h1>
    <h1>{{ interval2$ }}</h1>
  </div>
</template>

<script>
import { interval, pipe } from 'rxjs'
import { map } from 'rxjs/operators'
import { multiply } from 'ramda'

let mul = pipe(multiply, map)

let subscriptions = _ => {
  let interval$ = interval(1000)
  let interval1$ = interval$.pipe(mul(2))
  let interval2$ = interval$.pipe(mul(3))

  return { interval1$, interval2$ }
}

export default {
  name: 'app',
  subscriptions,
}
</script>

13 行

let mul = pipe(multiply, map)

我們發現兩個 pipe() 內都是 map(multiply(x)),這是重複的部分,而這正是 f(g(x)) 形式,也就是 Function Composition,因此可用 RxJS 的 pipe()multiply()map() 加以組合。

17 行

let interval1$ = interval$.pipe(mul(2))
let interval2$ = interval$.pipe(mul(3))

pipe() 就能使用新組合的 mul(),語意更清楚。

Conclusion

  • 可使用 map() 將既有 Observable 依照 function 規則建立新 Observable
  • RxJS 的 pipe() 會組合眾多 operator,由於都是 pure function,可輕易使用 pipe() 加以組合,實現 Function Composition

Reference

John Lindquist, Create RxJS Streams in the Vue.js Subscriptions Function
RxJS, map()