Effect 的 defect 要在哪里处理?
你写了 Effect.catch,也写了 catchTag,但 Effect.die(...) 抛出的东西照样穿过去,什么处理器都没触发。
这是设计:catch 和 catchTag 只处理 failure,碰不到 defect。 defect 代表程序已处于未预期的状态,业务逻辑不应假装能恢复,它应该交给程序最外层,或者少数边界上的专门工具。
这里默认你知道 failure 进 E、defect 不进(区别见 failure 和 defect 怎么区分)。下面看谁来看 defect,Effect.exit 与 Effect.result 有什么不同,以及 Effect.orDie 什么时候该用。
defect 该由谁来看?
三个典型位置:
- 程序最外层(即「边缘」,见 写第一个 Effect 程序):统一记录日志、返回 500、让进程退出。
Effect.exit:把结果(成功、failure、defect)整体具象化成一个Exit值,用于测试或需要完整观察的地方。Effect.catchCause或Effect.catchDefect:在少数边界上拦截 defect,通常只为记录后继续向外传播。
Effect.exit 和 Effect.result 有什么区别?
Effect.result 只把 failure 具象化成一个 Result 值(Success 或 Failure),自己不再失败,defect 仍然照常向外传播。Effect.exit 则连 defect 一起具象化。批量任务里用 Effect.result 让各个任务各自独立,见 并发。
什么时候该把 failure 升级成 defect?
用 Effect.orDie。当你确信某个 failure 在此处「不可能发生」或「发生即 bug」时使用,E 因此变成 never:
const mustExist = getUser("root").pipe(Effect.orDie)
// Effect<User, never>:若 root 不存在,视为缺陷orDie 是一个有分量的决定:你在对编译器说「这里我负责,别再让我处理它」。请只在你真的负责的时候用。
中断也归这里管吗?
不归。中断是第三种结局,不出现在 E 里,catchTag 和 Effect.catch 也接不住,机制见 fiber 与中断。另外,Effect 还有专门的错误上报机制,见 ErrorReporter。
本文内容整理自本站 Effect 教程中错误一章,原章节没有标明所用的 effect 版本,也没有记录示例的运行结果;这里的代码我没有重新运行验证,API 以你所用版本的 Effect 官方文档为准。