Effect v3 到 v4 如何把 Effect.fork 与 Effect.forkDaemon 迁移到 forkChild 与 forkDetach
【免费下载链接】effectBuild production-ready applications in TypeScript项目地址: https://gitcode.com/GitHub_Trending/ef/effect
Effect 仓库在 v4 中重命名了fork*系列组合子,并且所有 fork 变体都改为接受一个选项对象来控制 fiber 启动行为。如果你的 v3 代码里还有Effect.fork或Effect.forkDaemon调用,升级到 v4(仓库中packages/effect/package.json当前版本为4.0.0-rc.115)后这些旧名已经不存在,对应调用点必须改为Effect.forkChild或Effect.forkDetach。仓库中 migration/forking.md 是这次重命名的专门说明,migration/v3-to-v4.md 与 migration/annotations/effect__Effect.yaml 里有逐条 API 映射,本文按这两份文档把迁移路径走一遍。
先查重命名对照表,确定每个调用点改成什么
migration/forking.md 给出的完整映射如下:
| v3 | v4 | 说明 |
|---|---|---|
Effect.fork | Effect.forkChild | Fork as a child of the current fiber |
Effect.forkDaemon | Effect.forkDetach | Fork detached from parent lifecycle |
Effect.forkScoped | Effect.forkScoped | 名称不变,仍绑定当前Scope |
Effect.forkIn | Effect.forkIn | 名称不变,仍 fork 到指定Scope |
Effect.forkAll | — | 已移除 |
Effect.forkWithErrorHandler | — | 已移除 |
迁移时的基本动作就是全局搜索Effect.fork(和Effect.forkDaemon(,按上表替换;forkScoped和forkIn不需要改名,但签名上同样新增了可选的 options 对象,见下文。
迁移 Effect.fork 到 Effect.forkChild
v3 写法(文档示例):
import { Effect } from "effect" const fiber = Effect.fork(myEffect)对应的 v4 写法:
import { Effect } from "effect" const fiber = Effect.forkChild(myEffect)Effect.forkChild在 v4 源码中标注为@since 4.0.0,返回Effect<Fiber<A, E>, never, R>,即 fork 动作本身是一个 Effect,fiber 结果通过它拿到。仓库源码里的官方示例(见 packages/effect/src/Effect.ts 中forkChild的 JSDoc)展示了完整的验证方式:
import { Effect, Fiber } from "effect" const task = Effect.succeed("result") const program = Effect.gen(function*() { const fiber = yield* task.pipe(Effect.forkChild) const result = yield* Fiber.join(fiber) return result }) await Effect.runPromise(program) // => "result"把 fork 后的 fiber 用Fiber.join接回来,运行结果为"result",说明子 fiber 的返回值与原Effect.fork的语义一致。
迁移 Effect.forkDaemon 到 Effect.forkDetach
v3 写法(文档示例):
import { Effect } from "effect" const fiber = Effect.forkDaemon(myEffect)对应的 v4 写法:
import { Effect } from "effect" const fiber = Effect.forkDetach(myEffect)migration/annotations/effect__Effect.yaml 中Effect.forkDaemon的迁移备注是:forkDaemon 语义不变,只是改名为从父 fiber 生命周期中脱离的Effect.forkDetach。同样地,源码 JSDoc 示例给出了 detach 场景的验证路径:
import { Effect, Fiber } from "effect" const daemonTask = Effect.succeed("daemon result") const program = Effect.gen(function*() { const fiber = yield* daemonTask.pipe(Effect.forkDetach) return yield* Fiber.join(fiber) }) await Effect.runPromise(program) // => "daemon result"运行输出"daemon result",说明 detached fiber 的结果仍然可以通过Fiber.join观察。
使用 v4 新增的 fork 选项对象
v4 中forkChild、forkDetach、forkScoped和forkIn都接受同一个可选选项对象(见 migration/forking.md 与 packages/effect/src/Effect.ts 中的签名):
{ readonly startImmediately?: boolean | undefined readonly uninterruptible?: boolean | "inherit" | undefined }startImmediately— 为true时,fork 出的 fiber 立即开始执行而不是延迟执行;默认undefined(延迟)。uninterruptible— 控制 fork 出的 fiber 是否可被中断:true设为不可中断,"inherit"继承父 fiber 的中断性,undefined使用默认行为。
两种调用形态在文档中都给出了示例。data-last(curried,在pipe中传选项):
import { Effect } from "effect" const fiber = myEffect.pipe( Effect.forkChild({ startImmediately: true }) )data-first(effect 和选项同时传入):
import { Effect } from "effect" const fiber = Effect.forkChild(myEffect, { startImmediately: true })注意这个选项对象是 v4 新增的,v3 时代没有对应参数;如果 v3 代码里 fork 后靠“立即开始执行”的隐式行为做时序假设,迁移时要显式评估是否需要startImmediately: true,不要默认两者行为相同。
处理被移除的 forkAll 与 forkWithErrorHandler
如果你搜索时还命中了这两个已移除的组合子,migration/forking.md 与 migration/v3-to-v4.md 给出的替代方式一致:
Effect.forkAll:改用Effect.forEach + Effect.forkChild逐个显式 fork,或使用更高层的并发组合子。Effect.forkWithErrorHandler:改为Effect.forkChild + Fiber.await,即显式 fork 后通过观察 fiber 的结果来处理错误(文档也给出了Fiber.join作为观察 fiber 结果的方式)。
这两项不在“改名”范围内,是真正被删掉的 API,没有直接同签名的替代品。
验证迁移结果
仓库文档给出的可执行验证方式有两层:
- 编译检查:v4 源码中旧名已不存在。可以确认 packages/effect/src/Effect.ts 中没有
fork、forkDaemon、forkAll、forkWithErrorHandler的导出(实际存在的只有forkChild、forkDetach及未改名的forkScoped、forkIn)。因此迁移完成后,只要项目里所有Effect.fork(...)/Effect.forkDaemon(...)引用都能通过类型检查,就说明没有遗漏的调用点。 - 运行检查:按上文两个 JSDoc 示例各跑一遍,
forkChild示例应输出"result",forkDetach示例应输出"daemon result"(文档示例输出)。仓库内测试代码 ai-docs/src/09_testing/10_effect-tests.ts 中也有Effect.forkChild配合TestClock的实际用法可参考:
const fiber = yield* Effect.forkChild( Effect.sleep(60_000).pipe(Effect.as("done" as const)) ) // Move virtual time forward to complete sleeping fibers immediately. yield* TestClock.adjust(60_000)限制与边界
- 本文覆盖的是 fork 组合子的重命名迁移;
forkScoped和forkIn名称不变,但同样接受新的 options 对象,如果 v3 代码依赖其旧参数形态需要按 v4 签名调整。 - v4 当前处于 RC 阶段(
4.0.0-rc.115),fork 家族 API 在正式版前仍有变动可能,升级时建议锁版本并复核 migration/v3-to-v4.md 中Effect.fork*相关条目是否有更新。 - 若代码中通过
Micro.forkDaemon等入口调用,v4 中 Micro 已移除,统一改用Effect.forkDetach(见 migration/v3-to-v4.md 中Micro.forkDaemon条目)。
【免费下载链接】effectBuild production-ready applications in TypeScript项目地址: https://gitcode.com/GitHub_Trending/ef/effect
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考