当前位置: 首页 > news >正文

《WebAssembly指南》第九章:WebAssembly 导入全局字符串常量

WebAssembly 导入全局字符串常量能让开发者在 Wasm 模块中更轻松地使用 JavaScript 字符串 —— 因为它省掉了传统字符串导入时需要写的一大堆模板代码。

本文就来讲解导入全局字符串常量的工作原理。

传统字符串导入存在的问题

咱们先看看 WebAssembly 里传统的字符串导入是怎么实现的。在一个 Wasm 模块中,若要从名为 string_constants 的命名空间导入多个字符串,可使用以下代码片段:

// 从 "string_constants" 命名空间导入两个外部引用类型的全局变量(字符串)
(global (import "string_constants" "string_constant_1") externref)
(global (import "string_constants" "string_constant_2") externref)

随后在 JavaScript 中,你需要通过 importObject 提供这些待导入的字符串:

// 定义导入对象,为 Wasm 模块提供所需的外部资源
importObject = {// …(其他命名空间或资源)string_constants: {string_constant_1: "hello ",  // 第一个待导入的字符串string_constant_2: "world!",  // 第二个待导入的字符串// …(其他需要导入的字符串)},
};

在编译 / 实例化模块并调用其函数之前,还需执行以下步骤:

// 流式加载并实例化 Wasm 模块,传入导入对象
WebAssembly.instantiateStreaming(fetch("my-module.wasm"), importObject).then((obj) => obj.instance.exports.exported_func(),  // 调用模块导出的函数
);

但这种方式存在诸多不足,具体如下:

  1. 下载体积增大:每新增一个导入字符串,模块下载体积都会增加 —— 且增量不止字符串本身的大小。Wasm 模块中需定义导入全局变量,JavaScript 侧还需定义对应值,若模块需导入数千个字符串,额外体积会非常可观。
  2. 解析耗时增加:这些额外字节会延长解析时间,必须等解析完成后才能实例化 Wasm 模块。
  3. 优化不便:对 Wasm 模块做优化时(如编译时删除未使用的字符串常量),需同时修改 Wasm 模块和配套的 JavaScript 文件,操作繁琐。

此外,导入名支持任意 Unicode 字符串,因此开发者为方便(如调试),常直接将完整字符串作为导入名。此时 Wasm 代码需改写为:

// 直接用字符串内容作为导入名
(global (import "string_constants" "hello ") externref)
(global (import "string_constants" "world!") externref)

对应的 importObject 也需同步修改:

importObject = {// …(其他内容)string_constants: {"hello ": "hello ",  // 导入名与字符串值完全一致"world!": "world!",  // 导入名与字符串值完全一致// …(其他字符串)},
};

显然,这些模板代码完全可由浏览器自动处理 —— 而 “导入全局字符串常量” 特性正是为解决这一问题而生。

如何使用导入全局字符串常量

下面详细介绍导入全局字符串常量的具体使用方法。

JavaScript API

要启用导入全局字符串常量,只需在调用编译 / 实例化模块的方法时,添加 compileOptions.importedStringConstants 属性即可。该属性的值为一个命名空间,Wasm 引擎会自动用它填充导入的全局字符串常量。

代码示例如下:

// 编译 Wasm 字节码,通过 compileOptions 启用导入全局字符串常量
WebAssembly.compile(bytes, {importedStringConstants: "string_constants",  // 指定字符串导入的命名空间
});

如此一来,importObject 中便无需再罗列字符串了。

目前支持 compileOptions 对象的函数 / 构造函数包括:

  • WebAssembly.compile()
  • WebAssembly.compileStreaming()
  • WebAssembly.instantiate()
  • WebAssembly.instantiateStreaming()
  • WebAssembly.validate()
  • WebAssembly.Module() 构造函数

Wasm 模块相关特性

在 Wasm 模块中,现在可直接导入字符串字面量,只需指定与 JavaScript 中 importedStringConstants 一致的命名空间即可:

// 从 "string_constants" 命名空间导入字符串,并用 $h/$w 作为局部别名
(global $h (import "string_constants" "hello ") externref)
(global $w (import "string_constants" "world!") externref)

之后 Wasm 引擎会自动检查 string_constants 命名空间下所有导入的全局变量,并为每个导入名创建对应的字符串。

关于命名空间的选择建议

前文示例使用 string_constants 作为命名空间,仅为便于理解。在实际生产环境中,最佳实践是使用空字符串("")作为命名空间—— 这能显著减小模块文件体积。

原因是每个字符串字面量都会重复使用命名空间,若模块包含数千个字符串,空字符串命名空间节省的体积会非常明显。

若空字符串命名空间已用于其他用途,可考虑使用单字符命名空间(如 s' 或 #),以尽量减少体积开销。

需注意:命名空间通常由生成 Wasm 模块的工具链作者决定。一旦获取 .wasm 文件并准备嵌入 JavaScript,便无法随意选择命名空间 —— 必须使用该 .wasm 文件预期的命名空间。

导入全局字符串示例

现有一个可直接运行的导入全局字符串示例(打开浏览器 JavaScript 控制台即可查看输出)。该示例的逻辑为:在 Wasm 模块中定义一个函数,拼接两个导入的字符串并打印到控制台;导出该函数后,在 JavaScript 中调用它。

示例的 JavaScript 代码

以下是示例的 JavaScript 代码,可清晰看到如何通过 importedStringConstants 启用导入全局字符串:

// 定义常规导入对象,提供日志打印功能
const importObject = {m: {log: console.log,  // 为 Wasm 模块提供 console.log 功能},
};// 定义编译选项,启用所需特性
const compileOptions = {builtins: ["js-string"],  // 启用 JavaScript 字符串内置功能importedStringConstants: "string_constants",  // 启用导入全局字符串常量并指定命名空间
};// 加载、编译并实例化 Wasm 模块,最后调用导出的 main 函数
fetch("log-concat.wasm").then((response) => response.arrayBuffer())  // 将响应转为 ArrayBuffer(字节码).then((bytes) => WebAssembly.instantiate(bytes, importObject, compileOptions))  // 实例化模块.then((result) => result.instance.exports.main());  // 调用模块导出的 main 函数

示例的 Wasm 模块代码(文本形式)

以下是该 Wasm 模块的文本表示,注意其如何从指定命名空间导入字符串,并在 $concat 函数中使用这些字符串:

(module; 从 "string_constants" 命名空间导入两个字符串,分别命名为 $h 和 $w(global $h (import "string_constants" "hello ") externref)(global $w (import "string_constants" "world!") externref); 导入 JavaScript 字符串的拼接函数(func $concat (import "wasm:js-string" "concat")(param externref externref) (result (ref extern)))  ; 接收两个 externref 参数,返回 extern 引用; 导入日志打印函数(func $log (import "m" "log") (param externref))  ; 接收一个 externref 参数(待打印的字符串); 定义并导出 main 函数,作为入口点(func (export "main"); 调用 $concat 拼接 $h 和 $w,再将结果传给 $log 打印(call $log (call $concat (global.get $h) (global.get $w))))
)

http://www.dtcms.com/a/434576.html

相关文章:

  • ​​轻量之选:不依赖宝塔,用 NPM 与命令行部署在线工具箱​
  • RUST 静态生命周期和动态生命周期
  • Rocky Linux 8 远程管理配置指南(宿主机 VNC + KVM 虚拟机 VNC)
  • 北京网站快速备案建站手机网站
  • 第四章 信息系统管理
  • 【开发日记】记一次公司服务器中Redis服务问题排查
  • linux问题10--克隆后ip地址和源linux主机相同
  • 社交网站模版steam交易链接怎么改
  • AI重塑销售管理,突破“人”的能力边界|纷享AI主题研讨会宁波站圆满落幕
  • [C++项目组件] 后台服务器部署docker
  • 移动固态优盘坏道读写速率下降等测试
  • 解决django.db.utils.OperationalError: attempt to write a readonly database问题
  • Django SimpleUI 配置与优化详解
  • 从入门到精通:Django的深度探索之旅
  • 【数据结构】考研重点掌握:顺序查找算法实现与ASL计算详解
  • 大型网站建立1800做网站因为专业
  • 医疗AI平台化转型:从单点试点到体系化建设的互操作性与质量控制路径研究(上)
  • 做装修效果图的网站沈阳哪有wordpress
  • Linux命令行指令返回值data空降Python的机枪与大炮(DeepSeek)
  • c++中this指针使用bug
  • 网站源码中国有限公司外贸网站建设怎么制作
  • 哪家公司做网站专业安装wordpress主题放哪里
  • 我们为什么要封装 localStorage
  • 【AI论文】LongLive:实时交互式长视频生成
  • 企业网站推广总结网站降权是什么意思
  • 消息队列(面试)
  • Presto:一款免费开源的大数据SQL查询引擎
  • AI驱动的软件测试变革:从自动化框架到智能决策
  • The 2024 ICPC Asia Nanjing Regional Contest(2024南京区域赛EJKBG)
  • 面试场景题-