Effect 里会过期的资源怎么刷新?
同一个 LayerRef,先读两次版本号都是 1,invalidate 之后是 2,refresh 之后是 3,缓存命中时没有重建,失效和刷新各让版本前进一次。
单个值需要手动或定时刷新(token、远程配置),用 Resource;单个 Layer 构建出的服务需要失效重建,才用 LayerRef。 Resource 更轻,能用就别上 Layer。
两者都是「单个资源加刷新」,区别在抽象层级:LayerRef 缓存的是一个 Layer 构建出的整个 Context,Resource 缓存的是一个 Effect 的结果。资源的获取和释放仍然靠 Scope,不熟的话先看 Effect 怎么保证资源一定被释放?;需要按 key 区分资源的话,看 Effect 的 LayerMap、RcMap、Pool 该怎么选?。先看一段能跑的代码。
LayerRef 和 Resource 的刷新长什么样?
import { Context, Effect, Layer, LayerRef, Resource, Schedule } from "effect"
let n = 0
class Cfg extends Context.Service<Cfg, { readonly version: number }>()("app/Cfg") {
static readonly layer = Layer.effect(Cfg, Effect.sync(() => Cfg.of({ version: ++n })))
}
const readVersion = Cfg.use((cfg) => Effect.succeed(cfg.version))
const program = Effect.gen(function*() {
const ref = yield* LayerRef.make(Cfg.layer, { idleTimeToLive: "1 second" })
const a = yield* readVersion.pipe(Effect.provide(ref.get))
const b = yield* readVersion.pipe(Effect.provide(ref.get))
yield* ref.invalidate
const c = yield* readVersion.pipe(Effect.provide(ref.get))
yield* ref.refresh
const d = yield* readVersion.pipe(Effect.provide(ref.get))
console.log("LayerRef", a, b, c, d)
let tick = 0
const manual = yield* Resource.manual(Effect.sync(() => ++tick))
const x = yield* Resource.get(manual)
const y = yield* Resource.get(manual)
yield* Resource.refresh(manual)
const z = yield* Resource.get(manual)
console.log("manual", x, y, z)
const auto = yield* Resource.auto(Effect.sync(() => ++tick), Schedule.spaced("100 millis"))
const first = yield* Resource.get(auto)
yield* Effect.sleep("350 millis")
const later = yield* Resource.get(auto)
console.log("auto", first, later)
})
Effect.runPromise(Effect.scoped(program))输出是 LayerRef 1 1 2 3 和 manual 1 1 2:缓存命中不重建,invalidate 与 refresh 各让版本号前进一次。auto 的 later 比 first 大,说明后台在刷新;精确的刷新次数取决于调度,我没有把它当作契约。
Resource 的 manual 和 auto 有什么区别?
Resource 更轻:Resource.manual 由你调用 refresh,Resource.auto 按 Schedule 在后台刷新,Resource.get 永远返回当前缓存值。token、远程配置快照这类「一个值会过期」的需求,用它就够了。
LayerRef 比 Resource 多了什么?
LayerRef 是无 key 版的 LayerMap,底层是 RcRef。除了 invalidate,还有 refresh(失效并立即重新获取),以及 invalidationSchedule 做周期性失效。
要记住一条:失效不会撤销已借出的 context,它们在各自 scope 关闭前仍可用。
两个 API 稳定吗?
Resource 是 stable;LayerRef 是 unstable,小版本里 API 可能变,用的时候建议收在一个模块里。标签含义见 Effect v4 的稳定性标注:@stability 标签取代 unstable 目录。
版本是 effect@4.0.5。LayerRef 1 1 2 3和manual 1 1 2两行输出在这个版本上跑过;auto只确认了后台会刷新,没有验证具体刷新次数。稳定性标签来自扫描该版本dist/*.d.ts里的@stability。