很多平台都有 sleep()
,讓我們可以等待一段時間再繼續執行,這常見需求在 ECMAScript 該如何實現呢 ?
Version
macOS Catalina 10.15.5
VS Code 1.46.1
Quokka 1.0.307
Ramda 0.27.0
Wink-fp 1.20.69
Callback
let sleep = ms => f => setTimeout(f, ms)
let f = msg => ms => f => sleep(ms)(_ => f(msg))
f('Waited 3s')(3000)(console.log)
第 5 行
f('Waited 3s')(3000)(console.log)
提供 顯示訊息
與 延遲時間
,最後傳入 console.log()
顯示結果。
第 3 行
let f = msg => ms => f => sleep(ms)(_ => f(msg))
呼叫底層的 sleep()
。
第 1 行
let sleep = ms => f => setTimeout(f, ms)
所模擬的 sleep()
,底層使用 setTimeout()
實作。
Async Await
let sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
let f = msg => async ms => {
await sleep(ms);
return msg
}
f('Waited 3s')(3000) // ?
setTimeout()
本質是 asynchronous,會在 callback queue 等待,等 synchronous 都執行完才執行,在 ES5 只能使用 callback 實現。
但 ES6 迎來了 Promise 後,可改讓 sleep()
回傳 Promise 成為 asynchronous function,在 f()
內則使用 await()
等待 sleep()
後,才將 msg
回傳。
Promise Then
let sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
let f = msg => ms => sleep(ms).then(_ => msg)
f('Waited 3s')(3000) // ?
async await
都可等價改用 .then()
實現。
Pipeline
import { pipe, andThen, always } from 'ramda'
import { resolve } from 'wink-fp'
let sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
let f = msg => pipe(
sleep,
andThen(always(msg)),
andThen(resolve),
)
f('Waited 3s')(3000) // ?
.then()
優點是有 Function Pipeline 概念,但可惜 .then()
與 .resolve()
是掛在 Promise 上,而不是 free function,因此只能算 Method Chaining。
Ramda 提供了 andThen()
,為 Promise.prototype.then()
的 free function 版本。
Wink-fp 則提供了 resolve()
,為 Promise.resolve()
的 free function 版本,如此就能完整實現 Function Pipeline。
Wink-fp
import { pipe, andThen, always } from 'ramda'
import { resolve, sleep } from 'wink-fp'
let f = msg => pipe(
sleep,
andThen(always(msg)),
andThen(resolve),
)
f('Waited 3s')(3000) // ?
像 sleep()
這種常用的 function,Wink-fp 已經收錄,可直接使用。
sleep()
Number -> Promise
延遲一段時間後再執行
Number
:ms 延遲時間
Promise
:回傳為 Promise
Conclusion
- ES6 迎來
Promise
後,使得setTimeout()
這類 asynchronous function 有了新的用法,透過回傳Promise
,就不必再使用 callback 了 - Promise 有兩種用法,一種是透過 ES2017 的
async await
,風格接近 Imperative;另一種使用 ES6then()
,風格接近 FP - 但
then()
又不是真的 functional,嚴格算只能算 Method Chaining,但已經有 Function Pipeline 概念 - 透過 Ramda 的
andThen()
與 Wink-fp 的resolve()
,可使用 Ramda 的pipe()
加以 Function Pipeline 組合,則更具 FP 風格 sleep()
因為太常使用,已經收錄在 Wink-fp
Reference
MDN, setTimeout()
MDN, async function
MDN, Promise
Ramda, pipe()