|
| 1 | +--- |
| 2 | +title: Wasm Client SDK架构介绍 |
| 3 | +hide_title: true |
| 4 | +sidebar_position: 1 |
| 5 | +--- |
| 6 | + |
| 7 | +# Wasm Client SDK 架构介绍 |
| 8 | + |
| 9 | +## 前言 |
| 10 | + |
| 11 | +在现代 Web 开发中,许多场景都需要即时通讯功能,例如聊天、推送、协作等。然而,传统的前端方案往往依赖第三方云服务,带来高额成本和数据安全隐患。现在,借助 OpenIMSDK 这一开源项目,我们可以轻松构建自托管的即时通讯服务,并在客户端使用 WebAssembly (WASM) 进行高效的跨平台支持。本篇文章将介绍我们是如何基于 Go + WebAssembly + SQLite 虚拟化技术打造一套轻量且强大的 Web SDK 的。 |
| 12 | +## 1. 架构概述 |
| 13 | +本 SDK 的目标是让开发者能在浏览器环境下直接集成 OpenIMSDK 的即时通讯能力,同时尽可能复用原生(Go)版本的 OpenIMSDK Core,做到**“一套核心、多端复用”**。为此,我们选择了以下技术栈: |
| 14 | + |
| 15 | +### 1.1 Go + WebAssembly |
| 16 | +• 使用 Go 语言编写的核心逻辑,包括通信协议解析、消息拉取、消息同步等。 |
| 17 | +• 借助 WASM 将核心模块打包成可在浏览器执行的二进制。可在前端直接使用,无需重新实现大量逻辑。 |
| 18 | + |
| 19 | +### 1.2 WebAssembly (WASM) |
| 20 | +• 能将 Go 代码编译为可在浏览器运行的二进制,同时具备接近原生的性能表现。 |
| 21 | +• 提供必要的 JS 接口 (host functions),支持 SDK 与前端进行双向通信。 |
| 22 | + |
| 23 | +### 1.3 数据存储:SQLite + sql.js + IndexedDB |
| 24 | +• 使用 sql.js(JavaScript 版 SQLite)在浏览器中模拟本地数据库。 |
| 25 | +• 底层将数据存储在浏览器的 IndexedDB 中,但对开发者而言完全透明,仍然以原生 SQL 形式进行读写。 |
| 26 | +• 这种“虚拟化”处理方式能统一前端与原生端的数据库使用模式,减少多端差异带来的维护成本。 |
| 27 | + |
| 28 | +### 1.4 API 封装:JSON 通信 |
| 29 | +• 通过 JSON 数据格式在 JS 与 WASM 之间进行消息传递,降低语言间调用的复杂度。 |
| 30 | +• 封装一层更贴近 JavaScript 开发者习惯的接口,便于快速上手。 |
| 31 | + |
| 32 | +## 2、主要技术原理 |
| 33 | + |
| 34 | +### 2.1 Go + WebAssembly |
| 35 | +> 背景: |
| 36 | +> Go 语言在高并发和网络编程上具有天然的优势,同时能够方便地将逻辑抽象、封装成一个单独的核心模块。自 Go 1.11 开始,官方就支持将 Go 代码编译为 WebAssembly 文件,这为我们在 Web 端直接运行原生逻辑提供了可能。 |
| 37 | +
|
| 38 | +#### 编译过程 |
| 39 | + • 环境变量:在终端设置 GOOS=js GOARCH=wasm,将目标平台指定为 js/wasm。 |
| 40 | + • 生成 .wasm 文件:编译后会得到一个 .wasm 文件和一个配套的 wasm_exec.js,后者是 Go 官方提供的运行时,用来启动并管理 WASM 侧的 Go 代码。 |
| 41 | + |
| 42 | +#### 交互方式 |
| 43 | + • JSON 消息传递:由于 Go 与 JS 分处不同的运行环境,直接传递复杂数据结构较为困难。因此在 Go 侧,我们定义了一组统一的 JSON 接口用于接收/返回数据;在 JS 侧,通过序列化/反序列化实现两边通信,这样即便语言不同,也能无缝对接。 |
| 44 | + • 并发与网络:Go 依旧可以使用 Goroutine 等特性处理网络 I/O,浏览器端通过 WebSocket 或其他方式连接到自托管的 OpenIM 服务器,保持消息同步。 |
| 45 | + |
| 46 | +### 2.2 SQLite 虚拟化 |
| 47 | +> 为什么需要本地存储? |
| 48 | +> 即时通讯场景中,客户端往往需要将聊天记录、用户信息、会话列表等存储在本地,以便在断网或刷新后能快速恢复、离线查看。在桌面或移动端,SQLite 常被用作本地数据库;在浏览器环境,我们借助 sql.js 来模拟这一行为。 |
| 49 | +
|
| 50 | +#### sql.js 的工作原理 |
| 51 | + • sql.js: 这是一个将 SQLite 以 Emscripten 编译成 JavaScript 的项目,可在浏览器中直接执行原生的 SQL 语句。 |
| 52 | + • IndexedDB: 由于浏览器环境无法直接访问本地文件系统,sql.js 会将所有数据储存在内存或浏览器原生数据库 IndexedDB 中,并持久化。 |
| 53 | + • 统一数据库访问: 从业务层面看,所有客户端SDK都在使用“一套 SQL”读写,无需刻意区分。对于开发者来说,迁移或共享部分逻辑时非常简便。 |
| 54 | + |
| 55 | +### 2.3 前端 API 设计 |
| 56 | + |
| 57 | + • SDK 对外暴露的方法: 例如 login(), sendMessage(), getConversationListSplit() 等等;这些接口在内部会通过 JSON 字符串包装后调用 WASM 内部的对应函数。 |
| 58 | + • 事件/回调处理: 例如新消息通知、连接状态变更等事件,采用在 JavaScript 中设置事件监听的方式实现。一旦有消息从 WASM 返回,则通过相应事件进行通知。 |
| 59 | + |
| 60 | +## 3. 核心流程 |
| 61 | + |
| 62 | +import wasm_call_map from './assets/wasm_call_map.png' |
| 63 | + |
| 64 | +<p align="center"> |
| 65 | + <img src={wasm_call_map} alt="预览图" width="80%"/> |
| 66 | +</p> |
| 67 | + |
| 68 | +如上图所示,WASM SDK 的核心调用流程为: |
| 69 | +1. 用户发起对 SDK API 的调用(由 JS 层对外暴露)。 |
| 70 | +2. JS SDK 层将调用请求传递给 WASM 实现的 OpenIMSDK Core。 |
| 71 | +3. WASM Core 反向调用 JS 层,执行实际的 SQLite 读写逻辑(由 sql.js 实现)。 |
| 72 | +4. JS 数据库访问逻辑 完成 SQLite 操作,并将结果返回给 WASM Core。 |
| 73 | +5. WASM Core 对结果进行封装处理后,返回给 JS SDK 层。 |
| 74 | +6. 最终,JS 层 将处理结果返回给调用的用户。 |
| 75 | + |
| 76 | +> **性能优化**:JS 层执行的 SQLite 操作都被放到了 Web Worker 中,避免了 UI 线程的阻塞。 |
| 77 | +
|
| 78 | +## 4. 优点与局限性 |
| 79 | + |
| 80 | +### 优点 |
| 81 | +1. 高效复用,降低维护成本 |
| 82 | +• 由于各端(Web、桌面、移动)可以共用同一个 OpenIMSDK Core(Go 语言编写),只需编译到对应平台即可,大幅降低多人多端项目的开发与维护难度。 |
| 83 | +2. 接近原生性能 |
| 84 | +• WASM 代码运行效率高,对加解密、序列化、消息同步等较重负载处理更友好,让大型或复杂的即时通讯应用在浏览器环境下依然表现顺畅。 |
| 85 | +3. 稳定的本地缓存 |
| 86 | +• 通过 sql.js + IndexedDB 的本地缓存,用户可以在刷新、断网后仍能访问聊天记录和会话列表,提高了可用性与用户体验。 |
| 87 | +4. 安全性 |
| 88 | +• WebAssembly 运行在沙箱环境中,JS 与 WASM 间的通信边界清晰,可有效降低非预期的内存访问风险。 |
| 89 | +5. 快速迭代 |
| 90 | +• 当需要更新核心逻辑时,只要重新编译 .wasm 文件并替换部署即可;前端保持基本接口不变,升级成本较低。 |
| 91 | + |
| 92 | +### 局限性 |
| 93 | +1. 浏览器兼容性 |
| 94 | +• 现代浏览器(Chrome、Firefox、Safari、Edge 等)对 WebAssembly 的支持已经相对完善,但在老旧浏览器上可能会出现兼容性问题。 |
| 95 | +• IndexedDB 在某些特定环境下也存在奇怪的兼容性或容量限制,需要提前规划。 |
| 96 | +2. 学习与调试难度 |
| 97 | +• 虽然接入 SDK 时只要调用 JS 层封装的接口即可,但如果出现底层问题,排查 Go WASM 与 sql.js 交互会比单纯的 JS 调试更复杂。 |
| 98 | +3. 初次加载文件体积 |
| 99 | +• .wasm 文件可能相对较大,在网络环境较差时会有额外的加载时间。可配合 CDN、懒加载等策略进行优化。 |
| 100 | +4. Web Worker 通信开销 |
| 101 | +• 虽然将 SQLite 操作放到 Web Worker 能避免阻塞 UI,但也会带来一定的跨线程通信开销,需要在业务设计中平衡。 |
| 102 | + |
| 103 | + |
| 104 | +## 5. 总结 |
| 105 | + |
| 106 | +这套基于 WebAssembly 和虚拟化 SQLite 的 OpenIM Web SDK,在最大程度继承了 Go 端的网络与业务逻辑的同时,也充分利用了浏览器自带的 IndexedDB 进行本地持久化存储。对开发者而言,无需重写一套复杂的前端业务逻辑,即可获得接近原生性能的即时通讯能力。 |
| 107 | + • 共享核心:与其他平台(移动、桌面)的 SDK 共用同一份核心逻辑,减少重复开发。 |
| 108 | + • 本地缓存:用户可在浏览器端流畅查看消息历史,即便网络不佳也能完成大部分操作。 |
| 109 | + • 自托管:开发者对后端服务有完全掌控力,降低外部依赖所带来的数据安全与成本压力。 |
| 110 | + |
| 111 | +如果你正在寻找一款可在 Web 端灵活部署的开源即时通讯方案,或者想要掌控数据与服务端架构的自托管模式,欢迎尝试这款 SDK。它不仅能带来较高性能和安全性,也能简化你的前后端协作流程,实现快速交付。 |
| 112 | + |
| 113 | +更多资源 |
| 114 | +• [OpenIMSDK 官网](https://www.openim.io) |
| 115 | +• [OpenIMSDK 官方文档](https://docs.openim.io) |
| 116 | +• [GitHub 仓库](https://github.com/openimsdk) |
0 commit comments