點燈坊

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

在 Promise Chain 中使用 when()

Sam Xiao's Avatar 2020-11-18

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

Version

Ramda 0.27.1

when()

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

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

pipe(
  addAsync(1),
  then(when(equals(3), add(1))),
  then(add(2)),
  otherwise(console.error)
)(2) // ?

第 3 行

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

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

第 6 行

pipe(
  addAsync(1),
  then(when(equals(3), add(1))),
  then(add(2)),
  otherwise(console.error)
)(2) // ?

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

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

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

when() 包在 then() 之後還是回傳 Promise,因此繼續使用 then()

when000

Composition Law

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

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

let addSync = pipe(
  when(equals(3), add(1)),
  add(2)
)

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

第 5 行

let addSync = pipe(
  when(equals(3), add(1)),
  add(2)
)

若你覺得每個 function 都要 then() 很醜,由於 Promise 是 Monad,而 Monad 又是 Functor,因此 Promise 支援 Composition Law,可將 synchronous 部分單獨抽成 addSync()

第 10 行

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

如此整個 Promise Chain 就只剩下一個 then() 而已。

when001

Conclusion

  • 若要在 Promise Chain 使用 when() 有兩種方式:一種是將 when() 躲在 then() 內;另一種是乾脆使用 Compositon Law 將 synchronous 部分抽出新 function,最後一次傳給 then()

Reference

Ramda, pipe()
Ramda, when()
Ramda, andThen()