02 Promise 客户端 vs 效应客户端 本节摘要:上一节讲了 codegen 生成两种客户端,这一节详讲它们的取舍——Promise 客户端(轻量、零 Effect、给不用效应式编程的人)和效应客户端(富投影、保留全类型、给重度用户)。理解了这两种的差别和适用场景,你才知道为自己的需求选哪种。 一、两种客户端的设计哲学 先看它们背后的哲学差异: | Promise 客户端 | 效应客户端 设计哲学 | 最小依赖、最大兼容 | 深度集成、保留全部信息 依赖 | 零 Effect 依赖 | 依赖效应库 用户 | 不用效应式编程的人 | 用效应式编程的重度用户 它们服务的用户群体不同,所以设计取舍也不同。这不是「哪个更好」,而是「各管一类用户」。
本节摘要:上一节讲了 codegen 生成两种客户端,这一节详讲它们的取舍——Promise 客户端(轻量、零 Effect、给不用效应式编程的人)和效应客户端(富投影、保留全类型、给重度用户)。理解了这两种的差别和适用场景,你才知道为自己的需求选哪种。
先看它们背后的哲学差异:
| Promise 客户端 | 效应客户端 | |
|---|---|---|
| 设计哲学 | 最小依赖、最大兼容 | 深度集成、保留全部信息 |
| 依赖 | 零 Effect 依赖 | 依赖效应库 |
| 用户 | 不用效应式编程的人 | 用效应式编程的重度用户 |
它们服务的用户群体不同,所以设计取舍也不同。这不是「哪个更好」,而是「各管一类用户」。
Promise 客户端的设计目标是让任何 TS 项目都能用,不强制引入效应式编程。它的特点:
new 客户端(baseUrl) 构造,不用复杂初始化。await 或 for await 消费,标准 TS 写法。// 概念性示例:Promise 客户端的用法 const client = new OpencodeClient("http://localhost:4096"); const session = await client.session.create({ ... }); for await (const event of client.event.subscribe()) { ... }
这种客户端对「我只想调 API,不想学效应式编程」的用户非常友好——它的用法和任何基于 Promise 的 HTTP 客户端一样。
效应客户端的设计目标是保留全部类型信息,与效应生态深度集成。它的特点:
// 概念性示例:效应客户端的用法(返回 Effect) const result = await client.session.create({ ... }).pipe( Effect.catchAll(error => ...), Effect.timeout("5 seconds"), Effect.retry(...) );
这种客户端对「我整个项目都在用效应式编程」的重度用户友好——它能无缝融入效应工作流,享受效应的全部能力(可组合、可观测、可恢复)。
用一个例子感受两种客户端的差别——错误处理:
Promise 客户端:
try { await client.session.create({ ... }); } catch (e) { if (e instanceof ClientError) { // 区分领域/基础设施错误 } }
效应客户端:
client.session.create({ ... }).pipe( Effect.catchTag("DomainError", ...), Effect.catchTag("NetworkError", ...), Effect.retry({ times: 3 }), Effect.timeout("5 seconds") );
效应客户端的错误处理更精细(按错误标签分流)、更强大(内置重试/超时)。但代价是要懂效应式编程。Promise 客户端简单直接,但能力有限。
选型原则很清晰:
你的项目用效应式编程吗? │ ├─ 不用 ──► Promise 客户端(轻量、零门槛) │ └─ 用 ──► 效应客户端(深度集成、保留全类型)
绝大多数普通用户(做应用、写脚本、做集成)用 Promise 客户端就够——它简单、够用、不引入额外复杂度。只有项目本身就是效应式架构的重度用户,才值得用效应客户端。
💡 别为了「高级」选效应客户端:新手可能觉得「效应客户端更高级,我要用这个」。但如果你项目不是效应架构,引入效应客户端反而增加了学习成本和复杂度。选型看需求,不看「高级感」。
虽然两种客户端风格不同,但它们有一个重要的统一性:都从同一份 IR 生成,所以 API 形状完全一致。
也就是说,同一个 API(如 session.create),在 Promise 客户端和效应客户端里方法名、参数、返回数据结构都一样——只是返回形式不同(Promise vs Effect)。
这意味着:两种客户端可以互换。你先用 Promise 客户端快速开发,后来项目演进成效应架构,换成效应客户端——调用代码几乎不用改(方法名都一样),只改返回处理。
两种客户端讲清了,下一节讲最巧妙的用法——嵌入式 SDK。