资讯动态

effect-atom依赖注入详解:AtomRuntime如何无缝连接Effect Service与Layer

发布时间:2026/8/25 17:36:47 来源:尧图企业网站定制
effect-atom依赖注入详解AtomRuntime如何无缝连接Effect Service与Layer【免费下载链接】effect-atom项目地址: https://gitcode.com/gh_mirrors/ef/effect-atomeffect-atom 是面向 Effect 生态的响应式状态管理库其中的AtomRuntime是它的依赖注入核心只需一个 EffectLayer就能让所有 Atom 无缝使用Effect.Service定义的服务数据库、HTTP 客户端、日志器等。本文将带你快速搞懂 AtomRuntime 的工作原理与常见用法帮你把 Effect 的依赖注入能力平滑地带进前端状态管理场景。为什么需要 AtomRuntime在 Effect 里你习惯用Context.Tag即 ServiceLayer来做依赖注入但在 Atom 的世界里Atom.make默认跑在一个极简的默认 Runtime 上——它拿不到你精心装配的服务。这就带来三个典型痛点无法yield* SomeService普通 Atom 里拿不到任何自定义服务全局配置缺失Logger、Tracer、ConfigProvider 等横切能力无处安放多个 Atom 重复装配每个 Atom 都要手动 provide 一遍 Layer代码冗余。AtomRuntime 的解决方案非常直白把 Layer 编译成一个运行时 Atom之后再基于它创建的 Atom 天然共享同一份服务上下文。AtomRuntime 是什么先建立一个直觉Atom.runtime(layer)返回的AtomRuntimeR本身就是一个特殊的 Atom它的值是 Effect 的Runtime.RuntimeR。从类型定义就能看出它的结构见 Atom.ts 第 535 行起的AtomRuntime接口它是一个AtomResult.ResultRuntime.RuntimeR, ER即能求值出 Runtime 的 Atom携带一个layer字段保存装配用的Layer扩展出atom、fn、pull、subscriptionRef、subscribable五个构造方法用于创建注入了服务的各类 Atom。一句话总结AtomRuntime Layer 的 Atom 化运行时封装。如何从 Layer 创建 AtomRuntime三步快速上手以用户服务为例完整流程如下代码节选自项目 README.md第 1 步定义 Effect 服务class Users extends Effect.ServiceUsers()(app/Users, { effect: Effect.gen(function* () { const getAll Effect.succeed([{ id: 1, name: Alice }]) return { getAll } as const }), }) {}第 2 步用 Layer 创建 AtomRuntimeconst runtimeAtom Atom.runtime(Users.Default)第 3 步基于 Runtime 创建注入服务的 Atomconst usersAtom runtimeAtom.atom( Effect.gen(function* () { const users yield* Users // 这里可以随便 yield* 任意服务 return yield* users.getAll }), )之后组件里直接useAtomValue(usersAtom)即可完全不需要关心 Layer 的装配细节。源码解析AtomRuntime 如何把 Service 注入 Atom这是本文的核心答案藏在 Atom.ts 的context()工厂函数第 652 行起。它做了四件关键的事① Layer 被包装成一个 keepAlive 的 Atomconst layerAtom keepAlive( readable(() Layer.provideMerge(create, globalLayer)) )keepAlive保证 Layer 只装配一次、全局复用不会随 Atom 的闲置被回收。② Runtime 的构建流程第 674-681 行self.read function read(get: Context) { const layer get(layerAtom) const build Effect.flatMap( Effect.flatMap(Effect.scope, (scope) Layer.buildWithMemoMap(layer, options.memoMap, scope)), (context) Effect.provide(Effect.runtimeR(), context) ) return effect(get, build, { uninterruptible: true }) }注意Layer.buildWithMemoMap(layer, options.memoMap, scope)这一行所有 AtomRuntime 共享同一个Layer.MemoMap见第 712 行的defaultMemoMap。这意味着即使你创建了多个 Runtime同一个服务也只会被实例化一次——这是无缝的关键。③ 业务 Atom 如何拿到服务看RuntimeProto.atom的实现第 198-208 行atom(this: AtomRuntimeany, any, arg: any, options?: ...) { const read makeRead(arg, options) return readable((get) { const previous get.selfResult.Resultany, any() const runtimeResult get(this) // 先读 Runtime 本身 if (runtimeResult._tag ! Success) { return Result.replacePrevious(runtimeResult, previous) } return read(get, runtimeResult.value) // 再带着 Runtime 执行 }) }套路非常清晰runtimeAtom.atom(...)返回的 Atom在每次求值时先依赖get(this)自己这个 Runtime Atom拿到Runtime.RuntimeR后再交给makeRead。而真正执行 Effect 的makeEffect第 482 行起会把 Runtime 的 Context 与每个 Atom 独立的Scope、AtomRegistry合并后同步执行contextMap.set(Scope.Scope.key, scope) contextMap.set(AtomRegistry.key, ctx.registry) const scopedRuntime Runtime.make({ context: EffectContext.unsafeMake(contextMap), ... })④ 同步优先异步回退底层执行器runCallbackSync见 runtime.ts会先尝试同步完成fastPath快路径 SyncScheduler冲刷能同步就立即返回结果需要异步时才注册 Fiber Observer 等待回调。所以如果你的 Layer 都是纯内存服务Atom 会表现得像同步状态一样干脆。全局 Layer 注入addGlobalLayer 的最佳实践Tracer、Logger、ConfigProvider 这类所有 Runtime 都该有的横切能力不需要每个 Layer 手动提供一行搞定Atom.runtime.addGlobalLayer( Layer.setConfigProvider(ConfigProvider.fromJson(import.meta.env)), )对应源码在第 686 行每次调用都会把新 Layer 通过Layer.provideMerge合并进globalLayer之后每个新建的 AtomRuntime 都会自动带上它。其他实用 API 一览API用途runtimeAtom.atom(effect)创建注入了服务的只读/状态 AtomruntimeAtom.fn(effect)创建带服务的可调用函数 Atom如提交表单、RPC mutationruntimeAtom.pull(stream)从 Stream 分页拉取数据适合无限滚动、分页查询runtimeAtom.subscriptionRef(ref)订阅外部可订阅对象如 WebSocket配合Atom.family还能从键动态派生一组引用稳定的 AtomREADME 中userAtom示例是列表/详情类场景的常用组合。常见问题 FAQQAtomRuntime 和普通 Atom 有什么区别普通 Atom 跑在默认 Runtime 上只能访问Scope和AtomRegistryAtomRuntime 本身是产出 Runtime 的 Atom用它衍生的 Atom 才能访问你 Layer 里装配的全部服务。Q多个 AtomRuntime 之间服务会重复实例化吗不会。全局共享的memoMap保证同一服务只构建一次不同 Runtime 只是提供了不同的 R 组合。Q想在 React 里用需要额外配置吗不需要。从 atom-react 导入Atom即可Atom.runtime、useAtomValue、useAtomSet与本文用法完全一致。小结Atom.runtime(layer)把 Effect 的 Layer 变成 Atom 世界的运行时入口共享MemoMapkeepAlive让服务只实例化一次跨 Atom 无缝复用runtimeAtom.atom / fn / pull是注入服务的三大构造方法全局横切能力交给Atom.runtime.addGlobalLayer统一管理。掌握 AtomRuntime你就打通了 Effect 依赖注入与 effect-atom 响应式状态之间的最后一道桥。【免费下载链接】effect-atom项目地址: https://gitcode.com/gh_mirrors/ef/effect-atom创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价