孤独プログラマー譚

孤独死が近い。

RxJS if elseをどう表現するか

iif という関数がある。
iif自体は、Observableを返却する。

let arr = [1, 2, 3, 4, 5]
rx.from(arr)
.pipe(
  op.mergeMap(v => {
    return rx.iif(
      () => v % 2 === 0,
      rx.of(`偶数:${v}`),
      rx.of(`奇数:${v}`),
    )
  })
)
.subscribe(cl)
// 奇数:1
// 偶数:2
// 奇数:3
// 偶数:4
// 奇数:5


別にmapオペレータ内でif文を分岐させれば、十分な気がしてきた。

let arr = [1, 2, 3, 4, 5]
rx.from(arr)
.pipe(
  op.map(v => {
    if (v % 2 === 0) {
      return `偶数:${v}`
    } else {
      return `奇数:${v}`
    }
  })
)
.subscribe(cl)
// 奇数:1
// 偶数:2
// 奇数:3
// 偶数:4
// 奇数:5

RxJS 副作用のある処理はtap

ストリームと関係のない処理は、積極的にtapを使いたい。
パッと見で「副作用のある処理」が分かるようになる。見やすい。

let foo = rx.interval(1000).pipe(op.take(1))
foo.pipe(
  op.tap(cl) // 0と表示
)
.subscribe(cl) // 0と表示

function cl(v) {
  console.log(v)
}

RxJS Promise.all()はforkJoinで書き換え

Promise.all()。
すべてのPromiseが発火されるのを待つ。

let foo1 = getPromise(123)
let foo2 = getPromise('abc')
Promise.all([foo1, foo2])
.then(cl) // [123, 'abc']


forkJoinで書き換えられる。

let bar1 = rx.interval(100).pipe(op.take(1))
let bar2 = rx.interval(1000).pipe(op.take(1))
rx.forkJoin(bar1, bar2)
.subscribe(cl) // 1秒後に[0, 0]


pipeの中で使いたい場合は、mergeMapを使う。

rx.interval(1000).pipe(op.take(1))
.pipe(
  op.mergeMap(v => {
    let foo1 = rx.interval(100).pipe(op.take(1))
    let foo2 = rx.interval(1000).pipe(op.take(1))
    return rx.forkJoin(foo1, foo2)
  })
)
.subscribe(cl) // 2秒後に[0, 0]


共通メソッド。

function getPromise(v = 0) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(v), 1000);
  });
}

function cl(v) {
  console.log(v)
}

RxJS 2度クリック防止

よくある「非同期通信が走るボタンクリックで、2度押し禁止」。
RxJSはexhaustMapで対応できる。
わざわざフラグ用の変数を作る必要がない。

const rx = require('rxjs');
const op = require('rxjs/operators');

rx.interval(100).pipe(op.take(5))
.pipe(
  op.exhaustMap(v => rx.of(v).pipe(op.delay(200)))
  // 0, 2, 4 と表示される
  // 1, 3 はキャンセルされる
)
.subscribe(cl)