這邊要來講的是 Effect 的 runtime ,不要懷疑,就是執行 Effect 的 fiber 的那個
runtime ,你可能會覺得這有什麼好講的,我們平常不是用 Effect.runPromise
執行就好了嗎?你有沒有想過,除了 Effect.runPromise
時用的預設的 runtime 外,你還可以自訂 runtime 嗎?這篇就來看怎麼做,以及這樣做有什麼好處
我們之前一直都在用的 Effect.runPromise
好像都沒有好好的來看裡面到底有什麼東西,所以你覺得 Effect 的 runtime 到底要做什麼呢?從以前的內容來看, Effect 的 runtime 管理的東西有:
而我們平常用的 Effect.runPromise
實際上是使用 Runtime.defaultRuntime
在執行我們的 Effect ,而 Effect.runPromise
實際上相當於如下的 code
Runtime.runPromise(Runtime.defaultRuntime, Console.log('hi'))
如果你有看文件,你會發現這個 default runtime 的 type 是 Runtime<never>
,這代表什麼意思?代表著這個 runtime 沒有使用者自訂的 service ,只有預設的 service 而已。所以囉,如果你有一些 Effect 基本上肯定會用到某些 service ,那除了使用 Layer 管理外,也可以選擇用自訂的 Runtime 預先加入這些服務,避免每次都需要另外提供
若要使用自訂的 runtime 我們可以用 ManagedRuntime
,它可以傳入一個 layer ,並產生一個 runtime ,例如我們將前一篇中的 getDatabase
包成 service
class DatabaseService extends Effect.Service<DatabaseService>()("Database", {
accessors: true,
// 這邊要使用 scoped ,代表這個 service 需要開啟一個作用域
scoped: getDatabase
}) {}
// 使用包含了 DatabaseService 的 Layer 建立自訂的 runtime
const runtime = ManagedRuntime.make(DatabaseService.Default())
async function main() {
// 只要你是用這個 runtime 上的 runPromise ,你就不用另外提供 DatabaseService
await runtime.runPromise(Effect.gen(function*() {
yield* DatabaseService.query("query")
}))
// 關閉 runtime ,這邊會開始執行 service 的 cleanup
await runtime.dispose()
}
main()
這種 ManagedRuntime
其實還挺方便的,通常是用在當你的 Effect 在執行時需要特定的環境,例如你的程式需要資料庫,像我自己用到的情況是,我的程式需要一個 global 的 mutex ,因此需要全部使用同樣的 runtime ,有興趣可以看我的開源專案中是怎麼使用的
這篇我們學到了怎麼使用 ManagedRuntime
來管理執行環境,下一篇要來介紹一些應用場景,首先是怎麼在 React 中使用 Effect