iii Browser SDK(iii-browser-sdk)参考:把浏览器标签页变成 iii Engine 上的 Worker
2026/9/13 2:54:49 网站建设 项目流程

iii Browser SDK(iii-browser-sdk)参考:把浏览器标签页变成 iii Engine 上的 Worker

【免费下载链接】iiiEffortlessly compose, extend, and observe every service in real-time for the first time ever.项目地址: https://gitcode.com/GitHub_Trending/mo/iii

本文围绕 iii 0.12.0 文档中的 Browser SDK 参考页 展开,系统讲解iii-browser-sdk的完整公共 API 面:如何用一个 WebSocket 把浏览器标签页接入 iii engine、在页面中注册可被引擎回调的函数与自定义触发器、以三种动作模式(同步 / 即发即忘 / 入队)调用后端函数,以及ChannelReader/ChannelWriter流式通道、连接状态与错误语义。读完后你将能在前端代码中直接使用registerWorkerregisterFunctiontriggerTriggerAction等原语,并理解这些接口在仓库源码 sdk/packages/node/iii-browser 中的真实落点。

定位:独立实现,而非 Node SDK 的浏览器构建

文档原文档明确了一个前提:Browser SDK 是 Node SDK 之外的一个独立实现(standalone implementation),而不是 Node SDK 编译出来的浏览器产物。这一点在仓库中可以得到印证:

  • 包目录独立存在:sdk/packages/node/iii-browser,包名为iii-browser-sdk
  • package.json 的描述为 “III SDK for the browser — no OpenTelemetry, no Node.js dependencies”,且devDependencies中没有 OpenTelemetry 相关依赖;
  • 包声明"type": "module",通过tsdown同时产出 ESM/CJS(dist/index.mjs/dist/index.cjs),可直接在任意现代浏览器环境中以原生WebSocket运行。

这意味着浏览器端的取舍是刻意的:去掉结构化 Logger 与 OpenTelemetry 导出面,保留全部“Worker 原语”(函数、触发器、通道),使前端页面可以作为一个 iii Worker 参与整个系统的函数调用与事件驱动网络。

安装与包结构

安装方式(来自文档原文):

npm install iii-browser-sdk

从 package.json 的exports字段可以看到该包提供的四个入口:

导入路径内容
iii-browser-sdk根入口:registerWorkerTriggerActionChannelReaderChannelWriterIIIConnectionState
iii-browser-sdk/stream流式原语(IStreamStreamChangeEvent等类型)
iii-browser-sdk/state状态原语类型
iii-browser-sdk/helpers辅助工具

根入口的实际导出清单可以在 src/index.ts 中逐条核对:运行时值导出为ChannelReader/ChannelWriterRegistrationRejectedErrorEngineFunctions/EngineTriggers常量、registerWorkerTriggerAction;类型导出则覆盖InitOptionsStreamChannelRefTriggerRequestISdkFunctionRefTriggerTriggerTypeRefEnqueueResultMessageType等。

建立连接:registerWorkerInitOptions

文档签名:

function registerWorker(address: string, options?: InitOptions): ISdk;

address是 engine 的 SDK WebSocket URL。调用时连接会自动建立,没有单独的connect()步骤;返回的ISdk实例携带文档中列出的全部方法。仓库包 README 给出最小示例:

import { registerWorker } from 'iii-browser-sdk' const iii = registerWorker('ws://remotehost:3111')

InitOptions的可选字段(结合文档与包内类型定义):

字段类型说明
invocationTimeoutMsnumbertrigger()的默认超时(毫秒),默认30000
reconnectionConfigPartial<IIIReconnectionConfig>WebSocket 重连行为配置,IIIReconnectionConfig类型同样从包根导出
headersRecord<string, string>浏览器原生 WebSocket 不支持自定义请求头,认证应改用查询参数或 Cookie

注意部署侧的前置条件:浏览器连接的是 engine 的 worker-manager 监听器。包 README 提示需要在 engine 配置中为一个公开监听了(例如iii-worker-manager#browser)配置 RBAC 保护,且不应把私有监听器暴露给不可信的浏览器客户端。

常用方法

registerFunction:在标签页中注册可调用的函数

worker.registerFunction( functionId: string, handler: RemoteFunctionHandler, options?: RegisterFunctionOptions, ): FunctionRef;
  • functionId:唯一函数标识,使用::做命名空间(例如ui::show-notification);
  • handler:异步处理函数(data: TInput) => Promise<TOutput>,引擎侧任何 worker 都可以通过trigger回调它——这是“后端向浏览器推数据”的实时模式基础;
  • options:可选的descriptionrequest_format/response_formatmetadata
  • 返回值FunctionRefidunregister(),可随时把函数从引擎注销。

典型的浏览器侧函数注册(来自 包 README 的 Hello World):

iii.registerFunction('ui::show-notification', async (data: { title: string; body: string }) => { showToast(data.title, data.body) return { displayed: true } })

registerTrigger:把已注册函数绑定到触发器实例

worker.registerTrigger(trigger: RegisterTriggerInput): Trigger;

文档特别强调了一个 API 不对称点:触发器没有顶层的unregisterTrigger方法,注销必须通过返回句柄上的Trigger.unregister()完成RegisterTriggerInput的字段为type(触发器类型)、function_idconfig及可选id

registerTriggerType/unregisterTriggerType:自定义触发器类型

worker.registerTriggerType<TConfig>( triggerType: RegisterTriggerTypeInput, handler: TriggerHandler<TConfig>, ): TriggerTypeRef<TConfig>; worker.unregisterTriggerType(triggerType: RegisterTriggerTypeInput): void;

registerTriggerType让当前标签页声明并承载一种新的触发器类型handler是一个实现TriggerHandler的对象,含registerTrigger/unregisterTrigger两个异步方法,在触发器实例被引擎注册/注销时分别回调。返回的TriggerTypeRef<TConfig>提供idregisterTriggerregisterFunctionunregister等便捷方法,免去每次重复填写type字段。浏览器是自定义触发器类型的自然宿主之一——例如把“倒计时结束”“用户点击”这类纯前端事件做成可被引擎调度的触发器类型。

trigger:调用已注册函数

worker.trigger<TInput, TOutput>(request: TriggerRequest<TInput>): Promise<TOutput>;

TriggerRequest字段:

字段类型必填说明
function_idstring目标函数 ID
payloadTInput调用载荷
actionTriggerAction路由动作;省略即同步请求/响应
timeoutMsnumber覆盖InitOptions.invocationTimeoutMs的默认超时

Promise 的解析语义随action变化(文档原文要点):

  • 同步调用:解析为函数的返回值;
  • TriggerAction.Enqueue:解析为一个EnqueueResult(入队回执);
  • TriggerAction.Void:解析为undefined
// 同步调用 const users = await iii.trigger({ function_id: 'api::get::users', payload: {}, })

shutdown

worker.shutdown(): Promise<void>;

断开与 engine 的连接并释放资源,建议在页面卸载(beforeunload等时机)时调用。

Trigger actions:VoidEnqueue

TriggerAction是一个运行时常量对象,产出的值传给triggeraction字段:

TriggerAction.Void(); // fire-and-forget TriggerAction.Enqueue({ queue: "math" }); // route through iii-queue

其底层类型是联合类型:

{ type: "enqueue"; queue: string } | { type: "void" }

因此三种调用形态的完整示例为:

// 1) 同步请求/响应(默认) const result = await iii.trigger({ function_id: 'greet', payload: { name: 'World' } }) // 2) 即发即忘 await iii.trigger({ function_id: 'send-email', payload: { to: 'user@example.com' }, action: TriggerAction.Void(), }) // 3) 通过命名队列异步处理 const receipt = await iii.trigger({ function_id: 'process-order', payload: { orderId: '123' }, action: TriggerAction.Enqueue({ queue: 'orders' }), })

Enqueue会把调用路由进 engine 的 iii-queue 子系统,适合长耗时或可重试的任务,回执EnqueueResult可用于幂等判断。

Channels:基于原生 WebSocket 的流式通道

文档说明:ChannelReaderChannelWriter是包装 engine 流 WebSocket 的运行时类,直接使用浏览器的原生 WebSocket API;StreamChannelRef是在 SDK 各调用之间传递、用于标识某个通道端点的可序列化类型:

type StreamChannelRef = { channel_id: string; access_key: string; direction: "read" | "write"; }

StreamChannelRef的字段含义(access_key为访问凭证,direction区分读/写端)在包 README 与 0.11.0 版 自动生成 API 参考 中一致。通道端点本身由iii.createChannel(bufferSize)创建(bufferSize缺省 64),返回含reader/writerreaderRef/writerRef的对象,两个 ref 可以放进调用载荷发给其他 worker,实现跨 worker 的流式数据传输。

读写端方法面(文档列表与 src/channels.ts 源码逐一吻合):

方法说明
ChannelReaderonMessage(cb)注册文本消息回调
ChannelReaderonBinary(cb)注册二进制帧回调(Uint8Array
ChannelReaderreadAll()异步读取全部待发二进制数据
ChannelReaderclose()关闭读端连接
ChannelWritersendMessage(msg: string)发送文本消息
ChannelWritersendBinary(data: Uint8Array)发送二进制数据
ChannelWriterclose()关闭写端连接

一个典型的本地读取用法(源自包注释与 API 参考示例):

const channel = await iii.createChannel() // 把 writer ref 传给另一个函数,由它对端写入 await iii.trigger({ function_id: 'stream-producer', payload: { outputChannel: channel.writerRef }, }) channel.reader.onMessage((msg) => { console.log('Received:', msg) })

连接状态:IIIConnectionState

文档定义:

type IIIConnectionState = | "disconnected" | "connecting" | "connected" | "reconnecting" | "failed";

该字面量类型别名从包根导出。src/index.ts 中可以看到它实际由iii-constants模块再导出(连同IIIReconnectionConfig),这五个状态覆盖了浏览器网络波动下的完整生命周期:断线后 SDK 会进入reconnecting并按reconnectionConfig自动重连,重连耗尽后落入failed。前端可以用该状态驱动 UI 上的连接指示器。

Info 类型:FunctionInfoTriggerInfo

  • FunctionInfofunction_id(必填)、可选description、可选request_format/response_format、可选metadata
  • TriggerInfoidtrigger_typefunction_id(必填),可选config/metadata

文档同时划清了一条边界:WorkerInfoWorkerMetadata不属于本 SDK。当浏览器客户端需要其他 worker 的元数据时,应使用 engine 的 introspection 函数(参见 engine-sdk 参考的 engine 发现函数一节),即经由engine::workers::list等引擎内省函数完成,而不是在 Browser SDK 中寻找。

MessageType:线协议帧枚举

MessageType是一个运行时枚举,命名了 SDK 与 engine 之间交换的每一类 wire frame,调用方很少直接使用,但在调试协议交互时有用。从 0.11.0 版 自动生成参考 可以列出其成员全集:

InvocationResultInvokeFunctionRegisterFunctionRegisterServiceRegisterTriggerRegisterTriggerTypeTriggerRegistrationResultUnregisterFunctionUnregisterTriggerUnregisterTriggerTypeWorkerRegistered

这些帧名与包根导出的RegisterFunctionMessageRegisterTriggerMessageRegisterTriggerTypeMessage等消息类型一一对应:每个*Message类型都携带message_type字段标注帧类型,而RegisterFunctionOptionsRegisterTriggerInput等对外输入类型正是把message_type字段剥离后的Omit变体——调用方无需(也不应)手填message_type

本 SDK 不具备的能力面

文档明确列出了两个“不在此 SDK 中”的表面,理解它们能避免集成时的误用:

  1. Logger。Browser SDK 不附带结构化 logger;应使用浏览器内置console,并依赖 iii-observability worker 提供的 OpenTelemetry 表面做导出。这与 package.json 中 “no OpenTelemetry” 的定位一致。
  2. Error class。不存在IIIError/IIIInvocationError类;失败一律表现为携带Error实例的 rejected promise,需要自行检查message以及附加的code字段获取 engine 错误码。
try { await iii.trigger({ function_id: 'flaky::op', payload: {} }) } catch (err) { // err 是 Error 实例;engine 错误码在 (err as any).code console.error((err as Error).message) }

值得补充的是,src/index.ts 还导出了RegistrationRejectedError,用于函数/触发器注册被引擎拒绝(如命名冲突)的场景,它是当前包内唯一显式导出的错误类型。

工程验证路径

如果想在自己的项目里核对本文行为,仓库提供了完整的测试基建(均为只读参考):

  • sdk/packages/node/iii-browser/tests/channels.test.ts、triggers.test.ts、trigger-types.test.ts 等单测,基于mock-websocket验证线协议行为;
  • tests/integration 下的bridge.test.tschannels.test.tstrigger-type-lifecycle.test.ts等集成测试,针对真实 engine 验证通道与触发器类型生命周期;
  • exports.test.ts 校验包根导出面与文档所述公共 API 保持一致。

小结

iii-browser-sdk的公共面可以归纳为一句话:一个 WebSocket 连接 + 与 Node 端同构的 Worker 原语registerWorker建立连接;registerFunction/registerTrigger/registerTriggerType让浏览器标签页成为引擎可调度的 Worker;trigger配合TriggerAction.Void()/TriggerAction.Enqueue()覆盖同步、即发即忘与队列三种调用模式;ChannelReader/ChannelWriter提供基于原生 WebSocket 的双向流;IIIConnectionState暴露五态连接生命周期;而 Logger 与专用 Error class 是刻意裁剪掉的表面。所有接口细节都可以对照 sdk/packages/node/iii-browser 目录下的src/源码与tests/用例逐条验证。

【免费下载链接】iiiEffortlessly compose, extend, and observe every service in real-time for the first time ever.项目地址: https://gitcode.com/GitHub_Trending/mo/iii

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询