點燈坊

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

使用 resolveAfter() 延遲一段時間產生 Promise

Sam Xiao's Avatar 2019-09-28

若我們想延遲一段時間才產生 Promise,標準做法是 Promise Constructor 配上 Callback-based 的 setTimeout(),事實上搭配 Promise-based 的 sleep() 之後, 能用更 Functional 方法實現。

Version

macOS Mojave 10.14.6
VS Code 1.38.1
Quokka 1.0.244
Ramda 0.26.1
Wink-fp 0.1.0

Imperative

let resolveAfter = ms => val => new Promise(
  resolve => setTimeout(() => resolve(val), ms)
);

await resolveAfter(300)(2); // ?

欲實現 resolveAfter(),第一個 argument 傳入延遲時間,第二個 argument 傳入 data,將在延遲一段時間後傳回 data 的 promise。

因為會使用 setTimeout() 延遲一段時間,ECMAScript 標準做法是使用 promise constructor 的 resolve(),然後在 setTimeout() 的 callback 中呼叫 resolve() 產生 promise。

after000

Pipeline

import { pipe, then, always } from 'ramda';
import { sleep, resolve } from 'wink-fp';

let resolveAfter = ms => val => pipe(
  sleep,
  then(always(val)),
  then(resolve)
)(ms);

await resolveAfter(300)(2); // ?

事實上 setTimeout() 相當於 Wink-fp 的 sleep(),由於 sleep() 回傳 promise,可改用 pipe()sleep()resolve() 串起來。

可將 sleep() 想成 promise-based 的 setTimeout()

after001

Point-free

import { useWith, flip, then, thunkify } from 'ramda';
import { sleep, resolve } from 'wink-fp';

let resolveAfter = useWith(
  flip(then), 
  [sleep, thunkify(resolve)]
);

await resolveAfter(300)(2); // ?

也可將 resolveAfter() 進一步使用 useWith()thunkify() 使其 point-free。

after002

Wink-fp

import { resolveAfter } from 'wink-fp';

await resolveAfter(300)(2); // ?

事實上 Wink-fp 已經內建 resolveAfter(),可直接使用。

resolveAfter()
Number -> a -> Promise a
延遲一段時間後產生 promise

Number:延遲一段時間

a:任意型別的 data

Promise a:將 data 包成 promise 回傳

同理 Wink-fp 也提供 rejectAfter()

after003

Conclusion

  • setTimeout() 為 callback-based function,也因此必須搭配 promise coustructor 的 resolve(),若改用 promise-based 的 sleep(),則可使用 Ramda 的 pipe()then() 使其 pipeline,可再進一步使用 useWith()thunkify() 使其 point-free