news 2026/9/11 11:07:50

FlatBuffers JavaScript 使用指南:从 TypeScript 编译、Node.js 与浏览器读取到对象 API 实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
FlatBuffers JavaScript 使用指南:从 TypeScript 编译、Node.js 与浏览器读取到对象 API 实践

FlatBuffers JavaScript 使用指南:从 TypeScript 编译、Node.js 与浏览器读取到对象 API 实践

【免费下载链接】flatbuffersFlatBuffers: Memory Efficient Serialization Library项目地址: https://gitcode.com/GitHub_Trending/fl/flatbuffers

FlatBuffers 是一个零拷贝、内存高效的序列化库。本指南聚焦 JavaScript 生态下的使用方式:由于 JS 存在众多方言与模块体系,FlatBuffers 自 2.0 起改为由 TypeScript 源码转译分发,因此本文会完整演示如何从*.fbsschema 生成 TypeScript/JavaScript 代码、在 Node.js 与浏览器两种环境中读取 FlatBuffer 二进制数据,并结合仓库源码剖析BuilderByteBuffer的底层机制与对象化 API 的用法。

开始之前

在深入 JavaScript 用法之前,建议先阅读 Tutorial——该页面完整覆盖了所有受支持语言(包括 JavaScript)的通用 FlatBuffers 使用流程。本页则专门讲解 JavaScript 使用中的细节与注意事项。

同时,你应当先阅读 Building 构建出flatc编译器,并熟悉 Using the schema compiler 与 Writing a schema 两篇文档。

FlatBuffers JavaScript 库的位置与获取方式

FlatBuffers 的 JavaScript/TypeScript 库以 npm 包flatbuffers形式发布。在仓库内,对应的源码位于 ts 目录(TypeScript 源码)以及编译产物jsmjs目录,包配置见 package.json:

  • main指向js/flatbuffers.js(CommonJS 入口);
  • module指向mjs/flatbuffers.js(ESM 入口);
  • 发布内容包含js/**/*.jsjs/**/*.d.tsmjs/**/*.jsmjs/**/*.d.tsts/**/*.ts

如果想直接从源码使用,步骤如下:

  1. 在仓库根目录运行npm run compile,将 TypeScript 源码编译生成 JS 文件(该命令会执行tsc编译 CommonJS 与 ESM 两套产物,并用 esbuild 生成压缩版js/flatbuffers.min.js,详见 package.json 中的scripts.compile);
  2. 在你的项目中,把它当作普通依赖安装,以flatbuffers文件夹作为依赖来源。

tsc的编译配置可在 tsconfig.json 中看到:目标为es2020、模块体系为commonjs、输出目录./js,并开启strict严格模式,同时包含ES2020DOM两类 lib——后者正是为了支持浏览器环境(如TextEncoder/TextDecoder)而引入的。

使用 FlatBuffers JavaScript 库

注:更深入的完整示例请参考 Tutorial。

由于 JavaScript 存在大量不同的方言与模块类型(CommonJS、AMD、ESM、浏览器全局变量等),FlatBuffers 2.0 起将原生 JS 实现替换为从 TypeScript 转译的方案,统一维护一份 TypeScript 源码。

请参考 TypeScript usage 并将你的源码转译为所需的 JS 方言。在 JavaScript 中跑通的最小步骤为:

  1. 使用flatc--ts选项从*.fbs生成 TypeScript 文件;
  2. 使用tsc将生成的 TS 文件转译为所需的 JS 方言(tsc的安装方式可参考 TypeScript 官方下载页)。

Node.js 环境下的读取示例

以下代码演示在 Node.js(或使用模块加载器的 JS 环境)中读取一个已生成的 FlatBuffer 二进制文件:

// Note: These require functions are an example - use your desired module flavor. var fs = require('fs'); var flatbuffers = require('../flatbuffers').flatbuffers; var MyGame = require('./monster_generated').MyGame; var data = new Uint8Array(fs.readFileSync('monster.dat')); var buf = new flatbuffers.ByteBuffer(data); var monster = MyGame.Example.Monster.getRootAsMonster(buf);

这段示例与 tests/ts/JavaScriptTest.js 中的测试逻辑完全一致:测试脚本同样通过fs.readFileSync('../monsterdata_test.mon')读取 C++ 生成的二进制数据,再构造flatbuffers.ByteBuffer并调用getRootAsMonster完成反序列化,从而验证 JavaScript 运行时与 C++ 产出的二进制格式完全互通。

浏览器环境下的读取示例

以下代码是浏览器中基于 HTML/JavaScript 的示例(使用 HTML5FileReader读取用户选择的文件):

<script src="../js/flatbuffers.js"></script> <script src="monster_generated.js"></script> <script> function readFile() { var reader = new FileReader(); // This example uses the HTML5 FileReader. var file = document.getElementById( 'file_input').files[0]; // "monster.dat" from the HTML <input> field. reader.onload = function() { // Executes after the file is read. var data = new Uint8Array(reader.result); var buf = new flatbuffers.ByteBuffer(data); var monster = MyGame.Example.Monster.getRootAsMonster(buf); } reader.readAsArrayBuffer(file); } </script> <!-- 在浏览器中打开 HTML 文件,并从 <input> 字段选择 "monster.dat" --> <input type="file" id="file_input" onchange="readFile();">

注意浏览器场景需要先通过tsc将生成的monster_generated.ts转译为monster_generated.js,并以<script>标签或模块加载器方式引入。库本身对浏览器是友好的——tsconfig.json 中显式包含了DOMlib,而 byte-buffer.ts 中TextDecoder等 API 直接依赖标准 Web 平台能力。

读取字段值

拿到monster对象后,可以像下面这样访问字段:

var hp = monster.hp(); var pos = monster.pos();

在 JS/TS 运行时中,生成的访问器会通过ByteBuffer的 vtable 查询方法(如__offset__indirect__vector__string,见 byte-buffer.ts)按需、惰性地读取字段,这正是 FlatBuffers"零拷贝、只读取被访问字段"特性的体现。

在 JavaScript 中解析文本(JSON/Schema)

目前 JavaScript 尚不支持直接解析文本格式(Schema 与 JSON)。也就是说,将.fbsschema 或 JSON 数据直接转换成 FlatBuffer 二进制,只能借助flatc命令行工具(见 flatc.md)在 JS 运行时之外完成;JavaScript 端主要负责对已生成的二进制数据进行读取与写入。

深入:写入与对象化 API(Object Based API)

虽然原文档聚焦于读取场景,但 JavaScript/TypeScript 库同样完整支持写入。了解底层的Builder机制有助于你更合理地使用生成的代码。

Builder 的核心机制

写入端入口是 ts/builder.ts 中的Builder类,其核心设计如下:

  • 缓冲区自尾向前构建:所有标量写入方法(writeInt8writeInt32writeFloat64等)都先递减space再写入,保证后续"从后往前"写出、无需移动已写数据即可得到连续布局;
  • 自动扩容prep(size, additional_bytes)负责对齐计算,空间不足时调用growByteBuffer将缓冲区大小翻倍(超出 2GB 会抛错,见 builder.ts);
  • vtable 去重endObject会先写出当前对象的 vtable,再与历史 vtable 逐一比对,若完全一致则复用旧 vtable 并回退已写空间,从而压缩重复结构的空间开销(见 builder.ts);
  • 默认值省略addFieldInt32等字段写入方法在value == defaultValue且未调用forceDefaults(true)时不写入该字段,节省空间(见 builder.ts);
  • 字符串去重createSharedString通过string_maps缓存已写入的字符串,重复字符串只写一次(见 builder.ts)。

写入的完整流程可参考测试 tests/ts/JavaScriptTest.js:createString写字符串、createInventoryVector写向量、startMonster/addPos/endMonster构建表,最后用finish收尾。测试中特意用new flatbuffers.Builder(1)的极小初始容量来验证扩容算法,并循环clear()后重复构建以验证缓冲区容量不会随同尺寸负载增长(见 tests/ts/JavaScriptTest.js)。

对象化 API(--gen-object-api

FlatBuffers 的核心卖点是内存效率,因此基础 API 围绕"尽量少用内存"设计,这也让 API 显得繁琐(要求数据按前序构建、修改困难)。当效率不是第一优先级时,可以使用flatc --gen-object-api生成更便捷的对象化 API,将 FlatBuffer 与普通 JS/TS 对象互相转换:

// Autogenerated class from table Monster. let monsterobj = new MonsterT(); // Deserialize from buffer into object. Monster.getRootAsMonster(flatbuffer).unpackTo(monsterobj); // or let monsterobj = Monster.getRootAsMonster(flatbuffer).unpack(); // Update object directly like a regular TS class instance. console.log(monsterobj.name); monsterobj.name = "Bob"; // Serialize into new flatbuffer. let fbb = new flatbuffers.Builder(1); Monster.finishMonsterBuffer(fbb, monsterobj.pack(fbb));

对象化 API 的底层支撑定义在 ts/types.ts:IGeneratedObject接口要求实现pack(builder)(把对象写回缓冲区),IUnpackableObject<T>接口要求实现unpack()(把表展开为普通对象)。ByteBuffer还提供了createScalarListcreateObjList两个辅助方法(见 byte-buffer.ts),用于把向量字段便捷地展开为 JS 数组,正是对象化 API 展开向量时的核心工具。

测试与验证

仓库在 tests/ts 目录下提供了完整的 JS/TS 测试套件:

  • JavaScriptTest.js:主测试,覆盖读取 C++ 生成的二进制、JS 侧完整构建、对象化 API 的 pack/unpack、64 位整型、Unicode、模糊测试、共享字符串、结构体向量、字节向量等场景;
  • JavaScriptFlexBuffersTest.jsJavaScriptUnionVectorTest.jsJavaScriptUndefinedForOptionals.js等:针对 FlexBuffers、union 向量、可选字段等特性的专项测试;
  • TypeScriptTest.py:运行整套 TS/JS 测试的 Python3 脚本(需要安装 Node.js)。

运行仓库级测试可执行根目录 package.json 中的npm test,该命令会先npm run compile再进入tests/ts调用TypeScriptTest.py完成验证。

小结

在 JavaScript 中使用 FlatBuffers 的完整路径是:编写.fbsschema → 用flatc --ts生成 TypeScript 代码 → 用tsc转译为目标 JS 方言 → 通过 npm 包flatbuffers引入运行时库 → 用ByteBuffer包裹二进制数据后通过生成访问器零拷贝读取字段,或使用Builder从零构建数据。若追求开发效率,可配合--gen-object-api使用对象化 API;而 JSON/Schema 的文本解析目前仍依赖flatc工具链完成。

【免费下载链接】flatbuffersFlatBuffers: Memory Efficient Serialization Library项目地址: https://gitcode.com/GitHub_Trending/fl/flatbuffers

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

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

STM32L151RCT6低功耗MCU深度解析:从原理到实战的电池供电设计指南

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

作者头像 李华
网站建设 2026/9/11 11:07:46

RK3588边缘盒子RTSP服务内存失控与OOM Killer误杀深度复盘

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

作者头像 李华
网站建设 2026/9/11 11:06:31

分辨率指标解读:标定板选型与相机匹配实战指南

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

作者头像 李华
网站建设 2026/9/11 11:04:58

本科生论文写作:AI检测与学术规范工具实战指南

1. 项目概述&#xff1a;本科生如何高效规避AI写作陷阱 去年帮导师审阅本科生论文时&#xff0c;发现有个现象特别有意思&#xff1a;学生提交的作业里&#xff0c;那些过度依赖AI生成的段落就像沙滩上的贝壳一样显眼——表面光滑完美&#xff0c;但轻轻一敲就碎成渣。最典型的…

作者头像 李华
网站建设 2026/9/11 11:03:48

基于IGDT与阶梯碳交易的多能系统鲁棒优化调度Python实现

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

作者头像 李华
网站建设 2026/9/11 11:00:24

GEO优化公司推荐:按预算分层选不花冤枉钱

GEO优化公司推荐&#xff1a;按预算分层选不花冤枉钱 做GEO优化最怕两件事&#xff1a;钱花少了没效果&#xff0c;钱花多了浪费。很多企业决策者找GEO优化公司&#xff0c;一上来就问"你们多少钱"&#xff0c;但其实你真正该问的是"我这个阶段该花多少钱"…

作者头像 李华