news 2026/9/14 5:53:25

III Browser SDK 完整指南:在浏览器中注册函数、触发调用与实时流式通信

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
III Browser SDK 完整指南:在浏览器中注册函数、触发调用与实时流式通信

III Browser SDK 完整指南:在浏览器中注册函数、触发调用与实时流式通信

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

本文是 iii 项目 Browser SDK API 参考文档 的深度展开版。III Browser SDK(npm 包名iii-browser-sdk)让前端页面作为一个 III Worker 直接接入 III 引擎:通过一条原生浏览器 WebSocket 长连接完成函数注册、函数触发(同步 / 异步 / 队列)、自定义触发器类型、State 状态管理与 Stream 流式订阅。读完本文,你将掌握如何在浏览器中初始化 SDK、注册可被后端反向调用的函数、用TriggerAction控制调用路由、用iii-browser-sdk/stateiii-browser-sdk/stream子路径操作共享状态与实时数据,以及如何利用连接状态监听与重连配置构建健壮的实时前端。

为什么需要浏览器端 SDK

从仓库内 iii-browser-sdk README 可以看到,Browser SDK 的设计目标是把前端变成一个 III Worker,它带来四个核心能力:

  • 持久连接:一条 WebSocket 取代大量 HTTP 往返,避免轮询;
  • 双向通信:引擎可以调用注册在浏览器里的函数,后端 Worker 通过trigger()把数据实时推送到前端;
  • 同构 APIregisterFunctiontriggerregisterTrigger等原语与服务端 SDK 完全一致;
  • 零 Node.js 依赖:运行在任何具备原生WebSocket的浏览器环境,不带 OpenTelemetry 依赖(见 package.json 的description字段:"no OpenTelemetry, no Node.js dependencies")。

从源码结构看,SDK 主体位于 sdk/packages/node/iii-browser/src,由iii.ts(核心ISdk实现)、channels.tsstate.tsstream.tstriggers.tsiii-constants.tsiii-types.tstypes.ts等模块组成。本文对应的 API 参考文档 docs/reference/sdk-browser.mdx.skill.md 是由 docs/next/scripts/generate-api-docs.mts 依据这些源码中的 doc-comment 自动生成的。

安装

npm install iii-browser-sdk

包提供 ESM / CJS 双格式产物,并内置了多个子路径导出(exports字段定义在 package.json):

导入路径内容
iii-browser-sdk核心 API:registerWorkerISdkTriggerActionMessageType、各类注册输入与句柄类型
iii-browser-sdk/state状态管理:IStateStateGetInputStateSetInputStateUpdateInput
iii-browser-sdk/stream流式数据:IStreamStreamTriggerConfigUpdateOp系列原子操作
iii-browser-sdk/helpers辅助函数:createChannelcreateStream(见 helpers.ts)

初始化:registerWorker

import { registerWorker } from 'iii-browser-sdk' const worker = registerWorker('ws://localhost:49135')

签名

registerWorker(address: string, options?: InitOptions) => ISdk

address是 III 引擎的 WebSocket 地址(如ws://localhost:49135)。SDK 构造时会自动建立 WebSocket 连接(源码见 iii.ts 构造函数中的this.connect()),无需手动拨号。

InitOptions 完整字段

字段类型默认值说明
workerNamestringbrowser:<随机后缀>向引擎宣告的 Worker 名称。浏览器没有 pid 可区分,且引擎在每个命名空间内只允许一个同名的存活 Worker,因此 SDK 默认按客户端生成唯一名称,避免两个标签页共用固定名称时互相驱逐(见 iii.ts 与randomId()实现 iii.ts)
namespacestring引擎default命名空间Worker 注册与函数、触发器注册所在的命名空间。注意:浏览器没有process.env,因此没有环境变量兜底,必须显式传参;传入空字符串会被拒绝(见 iii.ts)
invocationTimeoutMsnumber30000worker.trigger()调用的默认超时(毫秒)
reconnectionConfigPartial<IIIReconnectionConfig>见下表WebSocket 断线重连行为
headersRecord<string, string>忽略浏览器 WebSocket 通过查询参数或 Cookie 鉴权,headers选项会被忽略

重连配置 IIIReconnectionConfig

重连采用指数退避 + 抖动策略,默认配置常量定义在 iii-constants.ts:

字段默认值说明
initialDelayMs1000起始延迟(毫秒)
maxDelayMs30000最大延迟上限(毫秒)
backoffMultiplier2指数退避倍数
jitterFactor0.3随机抖动因子(0–1),用于打散并发重连
maxRetries-1最大重试次数,-1表示无限重试

典型用法:

const worker = registerWorker('ws://localhost:49135', { invocationTimeoutMs: 10000, reconnectionConfig: { maxRetries: 5, initialDelayMs: 500 }, })

连接状态 IIIConnectionState

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

状态机在 iii-constants.ts 定义。测试用例(tests/connection.test.ts)验证了以下关键行为:

  • 订阅监听器会立即以当前状态触发一次,之后每次状态迁移都会触发;
  • 支持多个监听器同时订阅;
  • 存在致命错误(如WORKER_NAMESPACE_CONFLICT工作器名称冲突):最终状态为failed不再重连,且挂起的调用会被拒绝;
  • 非致命错误(如FUNCTION_NAMESPACE_CONFLICT):连接保持connected,不影响后续使用。

核心方法

registerTrigger:注册触发器

将触发器绑定到已注册的函数,事件发生时引擎调用目标函数。

签名

registerTrigger(trigger: RegisterTriggerInput) => Trigger

RegisterTriggerInput字段:

字段类型必填说明
typestring使用的已注册触发器类型标识(如storage::object-createdhttpcron
function_idstring触发器触发时调用的函数 ID
configunknown触发器类型专属配置,需匹配该类型期望的结构

示例

const trigger = worker.registerTrigger({ type: 'cron', function_id: 'my-service::process-batch', config: { expression: '0 */5 * * * * *' }, }) // 之后移除触发器 trigger.unregister()

实现细节(iii.ts):SDK 会在注册时用randomUUID()生成触发器实例 ID,并把触发器的命名空间默认解析为当前 Worker 的命名空间(而不是引擎的default),从而保证"触发器 → 函数"在同一个命名空间内解析成功。

registerFunction:注册浏览器本地函数

注册一个在浏览器会话本地执行的异步处理器。注意:HTTP invocation 配置是 Node.js SDK 的特性,浏览器 SDK 不接受该配置。

签名

registerFunction(functionId: string, handler: RemoteFunctionHandler, options?: RegisterFunctionOptions) => FunctionRef

RemoteFunctionHandler类型:

type RemoteFunctionHandler = (data: TInput) => Promise<TOutput>

RegisterFunctionOptions可选字段:description(函数描述)、metadata(任意元数据)、request_format/response_formatRegisterFunctionFormat,描述请求/响应结构)。

示例

// 本地处理器 const ref = worker.registerFunction( 'greet', async (data: { name: string }) => ({ message: `Hello, ${data.name}!` }), { description: 'Returns a greeting' }, ) // 之后移除函数 ref.unregister()

返回的FunctionRef包含id(函数唯一标识)和unregister()(从引擎移除该函数)。源码中的校验逻辑(iii.ts):空函数 ID 抛错、重复注册抛错,函数处理器会被包装进内部Map,等待引擎的InvokeFunction消息回调。

典型实时场景——后端推送数据到前端,无需轮询:

iii.registerFunction('ui::update-dashboard', async (metrics: { cpu: number; memory: number; requests: number }) => { document.getElementById('cpu')!.textContent = `${metrics.cpu}%` document.getElementById('memory')!.textContent = `${metrics.memory}MB` return null })

trigger:触发函数调用

通过请求对象调用函数,路由行为由action字段决定。

签名

trigger(request: TriggerRequest<TInput>) => Promise<TOutput>

TriggerRequest字段:

字段类型必填说明
function_idstring要调用的函数 ID
payloadTInput传给函数的输入数据
actionTriggerAction路由方式;省略则同步请求/响应
timeoutMsnumber覆盖默认调用超时(毫秒)

TriggerAction工厂对象(iii.ts 中的路由分支):

工厂方法行为返回类型
(省略action同步:等待函数返回Promise<TOutput>
TriggerAction.Enqueue({ queue })经命名队列异步处理;引擎入队后先确认Promise<EnqueueResult>(含messageReceiptId
TriggerAction.Void()即发即忘,不等待响应Promise<undefined>

示例

// 同步调用 const result = await worker.trigger<{ name: string }, { message: string }>({ function_id: 'greet', payload: { name: 'World' }, timeoutMs: 5000, }) console.log(result.message) // "Hello, World!" // 即发即忘 await worker.trigger({ function_id: 'send-email', payload: { to: 'user@example.com' }, action: TriggerAction.Void(), }) // 入队异步处理(队列必须在队列 Worker 的 queue_configs 中声明) const receipt = await worker.trigger({ function_id: 'process-order', payload: { orderId: '123' }, action: TriggerAction.Enqueue({ queue: 'orders' }), })

实现要点:同步调用会生成invocation_id,将 resolve/reject 挂入内部invocations表并设置setTimeout超时(默认 30000ms,超时后拒绝并移除挂起项);Void()路由直接发送InvokeFunction消息并立即返回undefined。引擎内置函数(engine::前缀)会被路由到default命名空间,避免泄漏到 Worker 命名空间(见invocationNamespace实现 iii.ts)。

registerTriggerType:注册自定义触发器类型

触发器类型定义了外部事件(HTTP、cron、queue 等)如何映射为函数调用。

签名

registerTriggerType(triggerType: RegisterTriggerTypeInput, handler: TriggerHandler<TConfig>) => TriggerTypeRef<TConfig>

RegisterTriggerTypeInput字段:id(类型唯一标识,如statedurable:subscriber)、description(人类可读描述)。

TriggerHandler字段:

字段类型必填说明
registerTrigger(config: TriggerConfig<TConfig>) => Promise<void>触发器实例注册时被调用
unregisterTrigger(config: TriggerConfig<TConfig>) => Promise<void>触发器实例注销时被调用

示例——自定义 cron 触发器类型

type CronConfig = { expression: string } worker.registerTriggerType<CronConfig>( { id: 'cron', description: 'Fires on a cron schedule' }, { async registerTrigger({ id, function_id, config }) { startCronJob(id, config.expression, () => worker.trigger({ function_id, payload: {} }), ) }, async unregisterTrigger({ id }) { stopCronJob(id) }, }, )

返回的TriggerTypeRef<TConfig>是一个带类型约束的句柄,提供便捷方法,调用方无需重复填写type字段:

方法说明
id触发器类型标识
registerTrigger(functionId, config)注册绑定到该触发器类型的触发器(自动把命名空间对齐到 Worker 的命名空间)
registerFunction(functionId, handler, config)注册函数并立即绑定到该触发器类型
unregister()从引擎注销该触发器类型

unregisterTriggerType:注销触发器类型

unregisterTriggerType(triggerType: RegisterTriggerTypeInput) => void
worker.unregisterTriggerType({ id: 'cron', description: 'Fires on a cron schedule' })

addConnectionStateListener:监听连接状态

订阅连接状态迁移,处理器会立即以当前状态触发一次,之后每次迁移触发,支持多个监听器,返回取消订阅函数。

签名

addConnectionStateListener(handler: (state: IIIConnectionState) => void) => () => void

示例

const unsub = worker.addConnectionStateListener((state) => { console.log('connection state:', state) }) // 之后停止接收更新 unsub()

shutdown:优雅关闭

shutdown() => Promise<void>
await worker.shutdown()

实现(iii.ts):置位关闭标志、清除重连定时器、拒绝所有挂起调用(错误为 "iii is shutting down")并清理资源。

状态管理:iii-browser-sdk/state

IState接口提供基于scope(命名空间)+ key的状态操作,通过iii-browser-sdk/state子路径导出(类型定义见 state.ts):

方法签名说明
get(input: StateGetInput) => Promise<TData \| null>按 scope 与 key 取值
set(input: StateSetInput) => Promise<StateSetResult<TData> \| null>创建或覆盖状态值
delete(input: StateDeleteInput) => Promise<DeleteResult>删除状态值
list(input: StateListInput) => Promise<TData[]>列出 scope 内全部值
update(input: StateUpdateInput) => Promise<StateUpdateResult<TData> \| null>对状态值应用原子更新操作

输入输出类型要点:

  • StateGetInput/StateDeleteInput{ scope, key }
  • StateSetInput{ scope, key, value }StateSetResult返回new_value(新值)与old_value(旧值,若存在);
  • StateUpdateInput{ scope, key, ops }ops有序的原子更新操作列表UpdateOp[]
  • StateUpdateResultnew_value/old_value之外还有可选的errors: UpdateOpError[],目前仅merge操作在输入违反校验边界时产出。

原子更新操作 UpdateOp

type UpdateOp = UpdateSet | UpdateIncrement | UpdateDecrement | UpdateAppend | UpdateRemove | UpdateMerge
操作字段语义
UpdateSetpath,value将指定路径字段设为值(空字符串 path 指向根值)
UpdateIncrementpath,by数值字段增加指定量
UpdateDecrementpath,by数值字段减少指定量
UpdateAppendpath?,value向数组追加元素 / 拼接字符串 / 在嵌套路径推入新值
UpdateRemovepath移除指定路径字段
UpdateMergepath?,value将对象浅合并进目标(根或嵌套位置)

MergePath类型:

type MergePath = string | string[]

省略path、传""[]均指向根值;传字符串表示第一层字段;传字符串数组表示嵌套路径,每个元素是字面量键,点号不解释为分隔符["a.b"]指向名为"a.b"的单个键,而非a → b)。

UpdateOpError提供稳定的错误信息结构:code(如"merge.path.too_deep")、messageop_index(出错操作在ops数组中的下标)、可选doc_url

更新校验边界

UpdateMergeUpdateAppend的引擎侧校验(见 sdk-browser.mdx.skill.md 的UpdateMerge/UpdateAppend条目):

  • 路径深度 > 32、路径段 > 256 字节、值深度 > 16、顶层键 > 1024 会被结构化错误拒绝;
  • 任何__proto__/constructor/prototype路径段或顶层键会被拒绝(防原型污染);
  • append语义:嵌套路径上缺失/为 null 的中间层自动创建;缺失叶子总是创建为数组;已存在的对象/标量叶子返回append.type_mismatch
  • 结果中的errors数组仅在出错时出现,无错时字段省略。

流式数据:iii-browser-sdk/stream

IStream<TData>接口用于自定义流实现,可覆盖引擎对某个流名的内置存储(通过helpers中的createStream传入,见 helpers.ts)。方法包括get/set/delete/list/listGroups,对应输入类型StreamGetInputStreamSetInputStreamDeleteInputStreamListInputStreamListGroupsInput,均以stream_name+group_id(+item_id)寻址。

流触发器配置

stream触发器——监听流条目变更:

字段类型必填说明
stream_namestring要监听的流名,仅该流的变更触发处理器
group_idstring设置后仅该组内变更触发
item_idstring设置后仅该条目变更触发
condition_function_idstring条件执行函数 ID,返回false时跳过处理器

处理器输入StreamChangeEventstreamNamegroupIdid?timestamptype: "stream",以及事件详情event: { data, type: "create" | "update" | "delete" }

stream:join/stream:leave触发器——监听订阅加入/离开:

StreamJoinLeaveTriggerConfig仅含可选condition_function_id;事件负载StreamJoinLeaveEventstream_namegroup_idid?subscription_id、可选context(来自StreamAuthResult)。

流认证

StreamAuthInputaddrheaderspathquery_params)→StreamAuthResult(可选context,认证后传给流处理器)。StreamContextStreamAuthResult["context"]的提取类型。

流式通道:Channel

Channel是用于Worker 与 Worker 之间数据传输的流式通道对,通过iii-browser-sdk/helperscreateChannel辅助函数创建(实现见 iii.ts):SDK 会调用引擎内置函数engine::channels::create,返回 writer/reader 两个端点及其可序列化引用。

import { createChannel } from 'iii-browser-sdk/helpers' const { writer, reader, writerRef, readerRef } = await createChannel(worker)
字段类型说明
writer/readerChannelWriter/ChannelReader通道写端 / 读端,使用原生浏览器 WebSocket
writerRef/readerRefStreamChannelRef可序列化端点引用,可放进调用 payload 传给其他 Worker

StreamChannelRef字段:channel_id(通道唯一标识)、access_key(认证访问密钥)、direction"read" | "write",标识读端或写端)。

RBAC 鉴权集成

Browser SDK 的类型体系完整覆盖 RBAC 代理 Worker 的接入契约:

  • AuthInput:WebSocket 升级时传给 RBAC 鉴权函数的输入,包含升级请求的headersquery_params(每个键映射为数组以支持重复键)、ip_address
  • AuthResult:鉴权函数返回值,控制 Worker 可调用的函数与上下文,字段与默认值:
字段默认值说明
allow_function_registrationtrue是否允许注册新函数
allow_trigger_type_registrationfalse是否允许注册新触发器类型
allowed_functions[]expose_functions之外额外允许的函数 ID
forbidden_functions[]即使匹配expose_functions也拒绝的函数 ID,优先级高于 allowed
allowed_trigger_types全部允许允许注册触发器的类型 ID
function_registration_prefix应用于该 Worker 注册的所有函数 ID 的前缀
context{}每次调用转发给中间件函数的任意上下文
  • MiddlewareFunctionInput:每次经 RBAC 端口的调用都会传给中间件函数,可检查、修改或拒绝调用,包含function_idpayloadcontext、可选action
  • 注册钩子OnFunctionRegistrationInput/ResultOnTriggerRegistrationInput/ResultOnTriggerTypeRegistrationInput/Result分别对应函数注册、触发器注册、触发器类型注册的映射/拒绝钩子——返回(可能被映射后的)字段,或抛异常拒绝注册;结果中省略的字段保持注册请求的原始值。

引擎常量与消息类型

  • EngineFunctions(iii-constants.ts):引擎内置函数路径,如engine::workers::registerengine::functions::listengine::functions::infoengine::workers::list/infoengine::triggers::list/infoengine::registered-triggers::list/info。命名注意点:LIST_TRIGGERS/INFO_TRIGGERS指触发器类型(模板),LIST_REGISTERED_TRIGGERS/INFO_REGISTERED_TRIGGERS指触发器实例(订阅行);旧的engine::trigger-types::list内置函数已移除,由engine::triggers::list承接;
  • EngineTriggersengine::functions-available(引擎触发器类型);
  • MessageType(wire 判别器):invokefunctioninvocationresultregisterfunctionregistertriggerregistertriggertypetriggerregistrationresultunregisterfunctionunregistertriggerunregistertriggertypeworkerregistered

命名空间语义(浏览器特性)

与 Node / Python / Go SDK 不同,浏览器没有环境变量可用,因此命名空间只能通过InitOptions.namespace与各调用参数显式传递(iii.ts):

  • 省略namespace→ 继承 Worker 的命名空间(Worker 未指定时落入引擎default);
  • 显式传入空字符串会被拒绝namespace is empty错误)——"未设置"与"设置为空"含义相反,??会转发空串,因此 SDK 选择直接抛错,避免歧义;
  • engine::前缀的内置函数调用,默认路由到default命名空间,防止引擎内置函数泄漏进 Worker 命名空间。

相关测试(tests/connection.test.ts)验证了:配置了命名空间时 register-worker 宣告载荷包含 namespace、未配置时省略、以及按调用序列化 per-call namespace 到InvokeFunction消息。

工程验证与测试

SDK 自带完善的测试体系(sdk/packages/node/iii-browser/tests):

  • 单元测试:connection.test.ts(连接状态机、致命/非致命命名空间冲突、重连行为)、triggers.test.tstrigger-types.test.tschannels.test.tshelpers.test.tsexports.test.ts(子路径导出完整性);
  • 集成测试(tests/integration):triggers.test.tstrigger-type-lifecycle.test.tsfunctions-available-trigger.test.tschannels.test.ts等,通过vitest.integration.config.ts运行,验证 SDK 与真实引擎的端到端交互;
  • 类型级测试:trigger-typing.type-check.tsmiddleware-input-namespace.type-check.ts在编译期校验泛型推导与 RBAC 中间件输入结构。

若需要修改 API 文档文案或格式,应编辑源码 doc-comment(sdk/packages/node/iii-browser/src 下的 prose)或 docs/next/scripts 中的生成脚本,再重新生成本文对应的参考文档,而不是直接编辑自动生成的 docs/reference/sdk-browser.mdx.skill.md。

小结

III Browser SDK 用"一条 WebSocket 连接"统一了前端的函数注册、调用、触发、状态与流式通信:registerWorker负责连接与重连,registerFunction让浏览器函数可被后端反向调用,trigger配合TriggerAction实现同步 / 即发即忘 / 队列三种路由,registerTriggerType支持自定义事件映射,iii-browser-sdk/stateiii-browser-sdk/stream提供带原子更新和严格校验的共享数据能力,RBAC 类型体系则保证了多租户与安全接入。配合连接状态监听与命名空间语义,你可以构建出实时、可观测、健壮的前端 Worker 应用。

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

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 5:52:45

ADMM图像去噪实战:Plug-and-Play框架与MATLAB实现解析

简介&#xff1a;这是一份面向图像处理学习者和科研人员的ADMM图像去噪MATLAB源码包&#xff0c;围绕交替方向乘子方法在图像去噪与去模糊中的应用展开&#xff0c;适合希望掌握优化算法落地实践的读者。资源共19个文件&#xff0c;以15个m脚本为主&#xff0c;涵盖总变分去噪、…

作者头像 李华
网站建设 2026/9/14 5:51:19

5款专业演示工具评测与AI PPT替代方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/14 5:51:16

LangChain实现情感聊天机器人记忆优化方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华