Rust + wasm 使用
一、wasm是什么
WebAssembly(WASM)是一个简单的机器模型和可执行格式,具有广泛的规范。它被设计为便携、紧凑,代码执行能够达到接近本机原生指令的执行速度。
作为一种编程语言,WebAssembly 由两种格式组成,它们以不同的方式表示相同的结构:
后缀为 .wat 的文本格式(称为“WebAssembly Text”),可以被人类理解,使用 S-表达式。
后缀为 .wasm 的二进制格式是较低级别的,人类无法读懂,它旨在供 wasm 虚拟机直接使用
1.为什么使用Wasm?
为什么要使用wasm,可以在JavaScript中使用c++代码或者rust代码从而提高代码效率。有几个原因可以说明使用WebAssembly的意义:
- 它允许在浏览器中执行用任何语言编写的代码。
- 这包括利用现有的库(数字、音频处理、机器学习等),这些库是用JavaScript以外的语言编写的。
- 根据所使用语言的选择,Wasm能够以接近原生的速度运行。这有可能使网络应用程序的性能特征更接近于移动和桌面的本地体验。
2.什么情况不适合使用功能Wasm?
WebAssembly的普及肯定会继续增长;然而,它并不适合所有的Web开发:
- 对于简单的项目,坚持使用JavaScript、HTML和CSS可能会在更短的时间内提供一个工作产品。
- 旧的浏览器,如Internet Explorer,不直接支持Wasm。
- WebAssembly的典型使用需要在你的工具链中添加工具,如语言编译器。如果你的团队优先考虑保持开发和持续集成工具尽可能的简单,使用Wasm将与此背道而驰。
3.为什么选择Rust+Wasm?
虽然许多编程语言都可以编译成Wasm,但我为这个例子选择了Rust。Rust是由Mozilla在2010年创建的,并在不断地普及。在2020年Stack Overflow的开发者调查中,Rust占据了 "最受喜爱的语言 "的位置。但在WebAssembly中使用Rust的原因不仅仅是潮流:
- 首先,Rust的运行时间很小,这意味着当用户访问网站时,发送到浏览器的代码更少,有助于保持网站的低足迹。
- Rust有出色的Wasm支持,支持与JavaScript的高级互操作性。
- Rust提供了接近C/C++级别的性能,但有一个非常安全的内存模型。与其他语言相比,Rust在编译代码时执行了额外的安全检查,大大减少了由空变量或未初始化变量引起的崩溃的可能性。这可以导致更简单的错误处理,并在发生意外问题时保持良好的用户体验的机会更高。
- Rust不是垃圾收集的。这意味着Rust代码可以完全控制内存的分配和清理时间,从而实现一致的性能–这是实时系统的关键要求。
二、rust代码打包成wasm
1. 安装 wasm-pack
一个构建、测试和发布 WASM 的 Rust CLI 工具,我们将使用 wasm-pack 相关的命令来构建 WASM 二进制内容。
2.在 Cargo.toml 文件中添加下列代码并保存,保存之后 Cargo 会自动下载依赖。
- cdylib 用来指明库的类型。
- wasm-bindgen 是一个简化 Rust WASM 与 JS 之间交互的库。它能够将如 DOM 操作、console.log 和 performance 等 JS 相关 API 暴露给 Rust 使用,能够将 Rust 功能导出到 JS 中,如类、函数等
[package]
name = "greeting"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
path = "src/main.rs" # 这个路径得有 用于包wasm
[dependencies]
wasm-bindgen = "0.2.83" # 用于包wasm
3.在main.rs中编写目标函数
// 标记为#[no_mangle]以确保其名称不被修改 用于wasm打包
#[no_mangle]
fn add(a: i32, b: i32) -> i32 {
return a + b;
}
4.编译构建wasm包
wasm-pack build
命令行执行这个代码,最终会得到pkg文件夹,在里面可以找到xxx.wasm
三、js中使用wasm包
方法一:直接读取二进制文件并对字节进行实例化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
<script type="application/javascript">
var exports;
fetch('/greeting_bg.wasm')
.then(response => response.arrayBuffer())
.then(bytes => WebAssembly.instantiate(bytes))
.then(result => {
exports = result.instance.exports;
console.log("导入完成")
// 在此处执行.wasm文件的导出函数或操作
console.log(exports.add(5, 3))
})
.catch(error => {
console.error('Failed to load and execute .wasm file:', error);
});
</script>
</html>
方法二:通过使用 instantiateStreaming 调用流式实例化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
<script type="application/javascript">
WebAssembly.instantiateStreaming(fetch("/greeting_bg.wasm")).then((obj) => {
const add = obj.instance.exports.add;
console.log(add(5,3));
})
</script>
</html>
学习参考博客
https://juejin.cn/post/7156102433581383716#heading-10
https://juejin.cn/post/7168351928949145614