當有 Function 回傳 Either,而後續的 Function 都在 Either 內執行時,卻又有 Function 回傳 Promise,這就造成 Either 內有 Promise 窘境,實務上該如何處理這種兩層 Monad 呢 ?
Version
Vue 3.0.11
Sanctuary 3.1.0
Promise Either
當沒有輸入任何 ID 時,會顯示 ID is empty
,且不會繼續呼叫 API 查詢價錢。
當輸入 ID 時,就會繼續呼叫 API 查詢價錢。
當 API 回傳 error response 時,則顯示 error message。
<template lang='pug'>
input(v-model='id')
button(@click='onClick') Submit
span {{ price }}
</template>
<script setup>
import { ref } from 'vue'
import { read, write } from 'vue3-fp'
import { pipe, map, andThen as then, otherwise, path, ifElse, isEmpty, thunkify } from 'ramda'
import { resolve } from 'wink-fp'
import { Left, Right, create, env } from 'sanctuary'
import getPrice from '/src/api/getPrice'
let { either, I } = create({ checkTypes: false, env })
let id = ref('')
let price = ref('')
let chkEmpty = ifElse(
isEmpty,
thunkify(Left)('ID is empty'),
Right
)
let onClick = pipe(
read(id),
chkEmpty,
map(getPrice),
map(then(path(['data', 'price']))),
either(resolve)(I),
then(write(price)),
otherwise(path(['response', 'data', 'error'])),
then(write(price))
)
</script>
26 行
let onClick = pipe(
read(id),
chkEmpty,
map(getPrice),
map(then(path(['data', 'price']))),
either(resolve)(I),
then(write(price)),
otherwise(path(['response', 'data', 'error'])),
then(write(price))
)
使用 pipe()
組合出 onClick()
:
read(id)
:讀取id
statechkEmpty
:檢查輸入是否為空白,並回傳 Eithermap(getPrice)
:呼叫getPrice()
從 API 查詢 price 並會回傳 Promisemap(then(path(['data', 'price'])))
:關鍵在此行,Promise 在 Either 內,因此只能map()
先拆第一層 Either,再用then()
拆第二層 Promise,所有的 function 都在map(then())
內either(resolve)(I)
:處理 Left Either,將錯誤訊息包成 Promise 回傳then(write(price))
:從 Resolved Promise 內取出資料寫入price
stateotherwise(path(['response', 'data', 'error']))
:從 Rejected Promise 內取出e.response.data.error
並回傳 Promisethen(write(price))
:將error
寫入price
state
20 行
let chkEmpty = ifElse(
isEmpty,
thunkify(Left)('title is empty'),
Right
)
使用 ifElse()
組合出 chkEmpty()
:
isEmpty
:檢查輸入是否為空白thunkify(Left)('name is empty')
:若輸入為空白,則回傳 Left Either,相當於 ExceptionRight
:正常值則回傳 Right Either
Conclusion
- Promise Either 乍聽很嚇人,其實只要把握用
map()
或chain()
處理 Either,用then()
處理 Promise,然後將所有 function 處理都寫在map(then())
內即可