點燈坊

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

在 Promise Chain 中使用 cond()

Sam Xiao's Avatar 2020-11-19

con() 若在 pipe() 中以 Function Pipeline 使用沒有問題,但若要搭配 Promise Chain 該如何使用呢 ?

Version

Ramda 0.27.1

cond()

import { pipe, andThen as then, otherwise, cond, equals, T, add } from 'ramda'
import { resolve } from 'wink-fp'

let addAsync = x => y => resolve(x + y)

pipe(
  addAsync(1),
  then(cond([
    [equals(2), add(1)],
    [equals(3), add(2)],
    [T, add(3)]
  ])),
  otherwise(console.error)
)(1) // ?

第 4 行

let addAsync = x => y => resolve(x + y)

addSync() 只是 x + y 的 asynchronous 版本,以 Promise 回傳。

第 6 行

pipe(
  addAsync(1),
  then(cond([
    [equals(2), add(1)],
    [equals(3), add(2)],
    [T, add(3)]
  ])),
  otherwise(console.error)
)(1) // ?

pipe() 組合過程中包含了 addAsync() ,由於回傳為 Promise,若要在之後使用 cond() 該如何使用呢 ?

由於 addAsync() 回傳 Promise,這使的之後的 function 也都要回傳 Promise,因此每個都要使用 then() 跑不掉。

then() 之內都是 Promise 內部值,因此 cond() 可安心取得,就當成 synchronous 思考即可。

cond000

Extract Function

import { pipe, andThen as then, otherwise, cond, equals, T, add } from 'ramda'
import { resolve } from 'wink-fp'

let addAsync = x => y => resolve(x + y)

let calculate = cond([
  [equals(2), add(1)],
  [equals(3), add(2)],
  [T, add(3)]
])

pipe(
  addAsync(1),
  then(calculate),
  otherwise(console.error)
)(1) // ?

第 6 行

let calculate = cond([
  [equals(2), add(1)],
  [equals(3), add(2)],
  [T, add(3)]
])

若你覺得 then() 之後要接一堆 function 很醜,也可將其抽出新 function。

12 行

pipe(
  addAsync(1),
  then(calculate),
  otherwise(console.error)
)(1) // ?

如此 then() 只要接 calculate() 即可,可讀性非常高。

cond001

propEq()

import { pipe, andThen as then, otherwise, cond, propEq, T, lensProp, set } from 'ramda'
import { resolve } from 'wink-fp'

let data = {
  title: 'Speaking JavaScript',
  price: 100
}

let fetchObj = o => resolve(o)

let priceLens = lensProp('price')

pipe(
  fetchObj,
  then(cond([
    [propEq('price', 100), set(priceLens, 110)],
    [propEq('price', 200), set(priceLens, 220)],
    [T, set(priceLens, 330)]
  ])),
  otherwise(console.error)
)(data) // ?

另一個常見的情況是處理 Object,則 cond() 可搭配 propEq(),至於寫入 Object 則可靠 Lens。

cond002

Extract Function

import { pipe, andThen as then, otherwise, cond, propEq, T, lensProp, set } from 'ramda'
import { resolve } from 'wink-fp'

let data = {
  title: 'Speaking JavaScript',
  price: 100
}

let fetchObj = o => resolve(o)

let priceLens = lensProp('price')

let writeObj = cond([
  [propEq('price', 100), set(priceLens, 110)],
  [propEq('price', 200), set(priceLens, 220)],
  [T, set(priceLens, 330)]
])

pipe(
  fetchObj,
  then(writeObj),
  otherwise(console.error)
)(data) // ?

13 行

let writeObj = cond([
  [propEq('price', 100), set(priceLens, 110)],
  [propEq('price', 200), set(priceLens, 220)],
  [T, set(priceLens, 330)]
])

也可將 then() 之後的 cond() 抽出新 funtion。

19 行

pipe(
  fetchObj,
  then(writeObj),
  otherwise(console.error)
)(data) // ?

如此 then() 只要接 writeObj() 即可,可讀性非常高。

cond003

Conclusion

  • 若要在 Promise Chain 使用 cond() 有兩種方式:一種是將 cond() 躲在 then() 內;另一種是將 cond() 抽出新 function,最後一次傳給 then()

Reference

Ramda, pipe()
Ramda, cond()
Ramda, andThen()
Ramda, propEq()
Ramda, lensProp()
Ramda, set()