错误与诊断
L10 Cause 的底层结构:扁平 reasons 数组
本课目标
- 读懂 Cause<E> 的数据结构
- 会用 guards 与 Cause.combine 分析复合失败
前置课时尚未完成:L09
可以自行跳转学习,但按顺序推进会更省力;学情分析会把这类缺口归入「前置缺口」。
为什么 E 不够
一个程序可能同时因为多个原因结束:两个并发任务都失败、finalizer 也失败、还有 fiber 被中断。若只保留一个 error 就会丢信息。Cause 的设计目标是无损保留所有失败事实。
v4 的 Cause 是扁平数组
← 代码可左右滑动 →
import { Cause, Effect, Exit } from "effect"
// Cause<E> ≈ { reasons: ReadonlyArray<Reason<E>> }
// Reason = Fail<E> | Die | Interrupt
const combined = Cause.combine(
Cause.fail("db down"),
Cause.die("bug in mapper")
)
combined.reasons.map((r) => r._tag) // ["Fail", "Die"]
const exit = await Effect.runPromiseExit(
Effect.all([Effect.fail("e1"), Effect.fail("e2")], { concurrency: 2 })
)
if (Exit.isFailure(exit)) {
exit.cause.reasons.filter(Cause.isFailReason).map((r) => r.error)
// 并发失败会被一起收集进同一个 reasons 数组
}💡 Cause.combine 只是把两个 reasons 数组拼起来;顺序与并发的组合方式不再编码进数据结构。
常用 API
- Cause.fail / die / interrupt / empty:构造单 reason 的 Cause(empty 即 reasons 为空)。
- Cause.hasFails / hasDies / hasInterrupts / hasInterruptsOnly:Cause 级判定。
- Cause.isFailReason / isDieReason / isInterruptReason:单个 reason 的类型收窄。
- Cause.combine / fromReasons / annotate:合并、从数组构造、附加注解。
- Cause.pretty:把整个 Cause 格式化成可读的多行错误报告。
⚠️ 文档勘误提醒
官方并发章节的部分打印示例里仍出现树形的 Parallel / Sequential 输出。v4 的 Cause 模块文档与数据结构是扁平 reasons 数组,以 Cause 模块为准;分析失败时请遍历 cause.reasons。
交互演练
关键术语
Reason
Cause 数组中的单个失败事实:Fail / Die / Interrupt
无损失败
不丢弃并行失败、finalizer 失败与中断来源
常见误区
× 把 Cause 当成单个 Error 对象,只取第一个 reason。
× 用 cause._tag 去 switch——v4 应遍历 cause.reasons。
随堂测验(即时反馈,答题计入掌握度)
Q1v4 中一个 Cause 如何表达「两个并发任务同时失败」?
Q2判断「这个 Cause 是否含有缺陷」用哪个?