核心值与组合
L06 组合与变换:map / flatMap / all / zip
本课目标
- 掌握常用算子的语义差异
- 知道 Effect.all 默认顺序执行
前置课时尚未完成:L05
可以自行跳转学习,但按顺序推进会更省力;学情分析会把这类缺口归入「前置缺口」。
变换 vs 串联
← 代码可左右滑动 →
import { Effect } from "effect"
const base = Effect.succeed(2)
Effect.map(base, (n) => n * 3) // 纯值变换
Effect.flatMap(base, (n) => loadUser(n)) // 串接另一个 Effect
Effect.andThen(base, () => Effect.log("ok"))// 忽略前值,继续
Effect.tap(base, (n) => Effect.log(n)) // 副作用观察,保留原值
Effect.zip(Effect.succeed("a"), Effect.succeed("b")) // 元组
Effect.all([t1, t2, t3], { concurrency: 2 }) // 受控并发💡 map 的回调返回普通值,flatMap 的回调必须返回 Effect。混用会导致类型错误或 Effect 被当成值。
⚠️ 并发默认是关的
Effect.all 不传 concurrency 时是顺序执行。想要并发必须显式给 { concurrency: 2 } 或 { concurrency: "unbounded" }。这是刻意的:并发语义必须由作者声明,不能被库偷偷引入。
顺序 / 有界 / 无界
- 默认顺序:前一个完成后才启动下一个,失败即短路。
- concurrency: number:最多 N 个在跑,适合限流保护下游。
- concurrency: "unbounded":全部同时启动,任一失败其余被中断。
交互演练
关键术语
短路
前一个失败后,后续组合子不再执行,错误沿链传播
concurrency 选项
number 有界 / "unbounded" 无界 / 省略则顺序
常见误区
× 以为 Effect.all 像 Promise.all 一样默认并行。
× 在 map 里返回 Effect,结果拿到一个 Effect 值而不是它的结果。
随堂测验(即时反馈,答题计入掌握度)
Q1Effect.all([a,b,c]) 不传 concurrency 时如何执行?
Q2map 与 flatMap 的分界是?