02 Promise 客户端 vs 效应客户端


文档摘要

02 Promise 客户端 vs 效应客户端 本节摘要:上一节讲了 codegen 生成两种客户端,这一节详讲它们的取舍——Promise 客户端(轻量、零 Effect、给不用效应式编程的人)和效应客户端(富投影、保留全类型、给重度用户)。理解了这两种的差别和适用场景,你才知道为自己的需求选哪种。 一、两种客户端的设计哲学 先看它们背后的哲学差异: | Promise 客户端 | 效应客户端 设计哲学 | 最小依赖、最大兼容 | 深度集成、保留全部信息 依赖 | 零 Effect 依赖 | 依赖效应库 用户 | 不用效应式编程的人 | 用效应式编程的重度用户 它们服务的用户群体不同,所以设计取舍也不同。这不是「哪个更好」,而是「各管一类用户」。

02 Promise 客户端 vs 效应客户端

本节摘要:上一节讲了 codegen 生成两种客户端,这一节详讲它们的取舍——Promise 客户端(轻量、零 Effect、给不用效应式编程的人)和效应客户端(富投影、保留全类型、给重度用户)。理解了这两种的差别和适用场景,你才知道为自己的需求选哪种。

一、两种客户端的设计哲学

先看它们背后的哲学差异:

Promise 客户端 效应客户端
设计哲学 最小依赖、最大兼容 深度集成、保留全部信息
依赖 零 Effect 依赖 依赖效应库
用户 不用效应式编程的人 用效应式编程的重度用户

它们服务的用户群体不同,所以设计取舍也不同。这不是「哪个更好」,而是「各管一类用户」。

二、Promise 客户端:轻量与兼容

Promise 客户端的设计目标是让任何 TS 项目都能用,不强制引入效应式编程。它的特点:

  • 同步构造:直接 new 客户端(baseUrl) 构造,不用复杂初始化。
  • 返回 Promise / 异步迭代:调用方法返回 Promise(或异步迭代用于流式),用 awaitfor await 消费,标准 TS 写法。
  • 统一错误类型:用一种错误类型(如 ClientError)区分「领域错误」和「基础设施错误」,调用方一个 catch 处理。
  • 零 Effect 依赖:不引入效应库,包体积小、学习成本低。
// 概念性示例: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 客户端一样。

三、效应客户端:富投影与深度集成

效应客户端的设计目标是保留全部类型信息,与效应生态深度集成。它的特点:

  • 保留解码值:返回的是解码后的强类型值(不是原始 JSON),类型安全。
  • 运行时 schema:带运行时 schema 信息,可以做更复杂的校验/转换。
  • 效应集成:返回效应流,可以用效应机制做错误处理、重试、可观测、并发控制等。
  • HTTP API 客户端:底层用效应的 HTTP 客户端,与效应的 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 客户端快速开发,后来项目演进成效应架构,换成效应客户端——调用代码几乎不用改(方法名都一样),只改返回处理。

七、本节要点回顾

  1. 两种客户端哲学不同:Promise 轻量兼容、效应富投影深度集成。
  2. Promise 客户端:同步构造、返回 Promise/异步迭代、统一错误类型、零 Effect 依赖。
  3. 效应客户端:保留解码值、带运行时 schema、效应集成、HTTP 中间件兼容。
  4. 错误处理举例:Promise 用 try-catch,效应用标签分流+内置重试超时。
  5. 选型:不用效应 → Promise;用效应 → 效应。别为「高级感」选效应。
  6. 统一性:同一 IR 生成,API 形状一致,只返回形式不同——可互换。

两种客户端讲清了,下一节讲最巧妙的用法——嵌入式 SDK。


发布者: 作者: 灏天文库 转发
评论区 (0)
U