點燈坊

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

使用 tryCatch() 處理 Exception

Sam Xiao's Avatar 2020-03-16

實務上難免會出現 Runtime Exception,此時可使用 Ramda 的 tryCatch() 產生新的 Function。

Version

macOS Catalina 10.15.3
VS Code 1.43.0
Quokka 1.0.277
Ramda 0.27.0

Imperative

Object Literal

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

let f = obj => obj.title.toUpperCase()
  
f(data) // ?

f() 想從 object 取得 title property 並轉成大寫。

trycatch000

Null

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

let f = obj => obj.title.toUpperCase()
  
f(null) // ?

若傳入 null,由於沒有 title property,因此出現 runtime exception。

trycatch001

Try Catch

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

let f = obj => {
  try {
    return obj.title.toUpperCase()
  } catch {
    return 'N/A'
  }

}
 
f(data) // ?
f(null) // ?

使用 try catch 攔截,若出現 exception 就顯示 N/A

trycatch002

Ramda

prop()

import { prop, toUpper, pipe } from 'ramda'

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

let f = pipe(
  prop('title'),
  toUpper
)

f(data) // ?

Ramda 會使用 pipe()prop()toUpper() 組合,這對正常 object 不是問題。

trycatch003

Null

import { prop, toUpper, pipe } from 'ramda'

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

let f = pipe(
  prop('title'),
  toUpper
)

f(null) // ?

若傳入 null,f() 就爆了。

不過 prop('title')obj.title 情況又不一樣。

prop('title') 若取不到 property 會回傳 undefined,使的 toUpper() 產生 exception,但 obj.title 是直接產生 exception。

trycatch004

tryCatch()

import { prop, toUpper, pipe, tryCatch, always } from 'ramda'

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

let f = pipe(
  prop('title'),
  tryCatch(toUpper, always('N/A'))
)

f(data) // ?
f(null) // ?

也因為 exception 只出現在 toUpper(),因此將 tryCatch() 用在 toUpper() 即可。

toCatch()
(…x → a) → ((e, …x) → a) → (…x → a)
若第一個 function 產生 exception,則回傳第二個 function,否則回傳第一個 function

trycatch005

Conclusion

  • 傳統 try catch 是 imperative 用在處理 variable,而 tryCatch() 是用在處理 function,若有 exception 則回傳另一個 function,適合 function composition

Reference

Ramda, tryCatch()
Ramda, prop()
Ramda, toUpper()
Ramda, pipe()
Ramda, always()