ECMAScript 2018 的 finally()
與 try catch finally
的確可處理 Fulfilled Promise 與 Rejected Promise 共用邏輯,但可惜還不夠 Functional,透過 Wink-fp 的 eventually()
可使 Promise Chain 也能 Function Composition。
Version
macOS Mojave 10.14.6
VS Code 1.38.1
Quokka 1.0.248
ECMAScript 2018
Ramda 0.26.1
Wink-fp 0.0.11
finally()
let fetchData = () => Promise.resolve('Hello World');
fetchData().then(
x => {
console.log(x);
console.log('Fetch completed');
}
).catch(
e => {
console.log(e);
console.log('Fetched completed');
}
);
若無論是 fulfilled
Promise 或 rejected
Promise,最後我們都希望印出 Fetched completed
。
若只有 then()
與 catch()
,則 fulfilled handler 與 rejected handler 都必須包含 console.log('Fetched completed')
。
let fetchData = () => Promise.resolve('Hello World');
fetchData()
.then(x => console.log(x))
.catch(e => console.log(e))
.finally(() => console.log('Fetched completed'));
ES2018 提供了 finally()
,可將 fulfilled handler 與 rejected handler 重複部分重構到 finally()
的 callback 中。
Try Catch Finally
let fetchData = () => Promise.resolve('Hello World');
try {
let x = await fetchData();
console.log(x);
} catch(e) {
console.log(e);
} finally {
console.log('Fetched completed')
}
自從 ES2017 可將 await
用於 try catch
block 中之後,自然也能將 finally()
寫在 finally
block 內。
這種寫法個符合 imperative 與 synchronous 習慣。
eventually()
import { then, otherwise, pipe } from 'ramda';
import { resolve, log } from 'wink-fp';
let fetchData = () => resolve('Hello World');
let eventually = cb => ps => ps.finally(cb);
let fn = pipe(
fetchData,
then(log),
otherwise(log),
eventually(() => console.log('Fetched completed'))
);
fn();
我們也可自行建立 eventually()
將 Promise.prototype.finally()
包成 function,如此就能使用 pipe()
以 pipeline 方式呈現 promise chain。
Wink-fp
import { then, otherwise, pipe, always } from 'ramda';
import { resolve, log, eventually } from 'wink-fp';
let fetchData = () => resolve('Hello World');
let onEventual = pipe(
always('Fetched complete'),
log
);
let fn = pipe(
fetchData,
then(log),
otherwise(log),
eventually(onEventual)
);
fn();
Wink-fp 已經提供 eventually()
,可直接使用。
eventually()
(a -> b) -> (Promise e a) -> (Promise e b)
Promise.prototype.finally()
的 function 版本
(a -> b)
:synchronous function
Promise e a
:data 為 promise
Promise e b
:回傳亦為 promise
Function Composition
import { then, otherwise, compose, always } from 'ramda';
import { resolve, log, eventually } from 'wink-fp';
let fetchData = () => resolve('Hello World');
let onEventual = compose(
log,
always('Fetched comple')
);
let fn = compose(
eventually(onEventual),
otherwise(log),
then(log),
fetchData
);
fn();
既然能使用 pipe()
達成 pipeline,反向使用 compose()
就是 function composition 了。
Conclusion
finally()
能避免then()
與catch()
中有重複邏輯- 也可使用
try catch finally
block,繼續使用 imperative 思維 seventually()
為Promise.prototype.finally()
的 function 版本,因此可使用 function composition