Rust与Node.js互操作:构建高性能与安全的桥梁
本文从动机与背景出发,详细介绍如何在 Node.js 中调用 Rust 代码(以及反向调用),包括基于 Neon、napi-rs、WebAssembly (wasm-bindgen) 等多种方案的实现细节。文中配以示例代码与 ASCII 图解,帮助你快速上手并理解底层工作原理。
目录
背景与动机
Node.js 在 I/O 密集型场景表现优异,但对于 CPU 密集型任务(如加密、图像处理、大规模数值计算等),纯 JavaScript 的性能往往难以满足需求。此时将性能关键模块用 Rust 重写,结合 Node.js 的生态与易用性,就能构建高性能且安全的应用。
- 性能优势:Rust 编译后生成机器码,运行接近 C/C++,可以显著提升计算密集型任务的速度。
- 内存安全:Rust 的所有权和借用(ownership & borrow)机制在编译期保证内存安全,避免常见的空指针、数据竞态等问题。
- 生态互补:Node.js 负责网络、I/O、业务协调,Rust 负责核心计算,两者结合可以取长补短。
但要让二者协同工作,需要在运行时建立“桥梁”,主要有以下几种路径:
- Neon / N-API:以 Node.js 原生模块(Native Addon)的形式,直接调用 Rust 代码。
- napi-rs:基于 Node.js 官方的 N-API 接口,通过 Rust 宏和库封装,简化绑定过程。
- WebAssembly:将 Rust 编译为 .wasm 模块,再在 Node.js 中以 WebAssembly 的形式加载、调用。
下文将分别介绍这三种主流方法,并通过示例与图解帮助理解。
互操作的三条主线
1. Neon:Rust → Node.js 原生扩展
- 特点:Neon 是 Rust 社区出品的专门用于编写 Node.js 原生扩展的工具链。它采用 Rust 代码直接生成 Node.js Addon(二进制 .node 文件),通过 FFI 与 V8 引擎交互。
- 适用场景:需要最高性能且愿意编写少量“胶水层”(glue code)时使用。
2. napi-rs:基于 N-API 的桥接
- 特点:napi-rs 基于 Node.js 官方的 N-API(ABI 稳定的原生接口),通过 Rust 的宏与类型系统,将 N-API 封装为易用的 Rust 接口。
- 优点:兼容性好(N-API 保证跨 Node.js 版本 ABI 稳定)、实现方式与 Neon 类似,但绑定过程更简洁。
3. WebAssembly(wasm-bindgen):跨平台模块化
- 特点:Rust 编译为 WebAssembly 模块,借助
wasm-bindgen
生成 JavaScript 绑定封装,可在浏览器与 Node.js 环境中运行。 - 适用场景:需要在浏览器、Electron、Node.js 等多平台复用同一段 Rust 逻辑,或对发行包大小与跨平台兼容性要求较高时使用。
环境准备
安装 Rust 开发环境
- 官网:https://www.rust-lang.org
推荐使用
rustup
:curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source ~/.cargo/env rustup update
验证:
rustc --version cargo --version
安装 Node.js
- 推荐 Node.js 16 及以上(Neon 与 napi-rs 均依赖较新版本的 N-API)。
验证:
node --version npm --version
选择包管理器
- 本文示例以 npm 为主,也可使用 Yarn。
全局安装构建工具
用于编译 Node 原生模块:
npm install -g neon-cli # 若使用 Neon npm install -g @napi-rs/cli # 若使用 napi-rs
- 如果使用 Neon 需安装
neon-cli
,napi-rs 则可使用napi-cli
。
创建工作目录
mkdir rust-node-interop cd rust-node-interop npm init -y
方案一:使用 Neon 构建 Native Module
什么是 Neon?
Neon 是一个基于 Rust 的工具集和库,帮助开发者将 Rust 代码编译为 Node.js 原生扩展(即生成 .node
动态库),并通过 Neon 提供的 API 将 Rust 函数暴露给 JavaScript。其底层通过 Node.js 的 N-API 或 V8 API(取决于 Neon 版本)来与 Node.js 进程通信。
优点:
- 性能接近 C/C++ 插件,无额外运行时开销
- Rust 提供内存安全,减少不少低级错误
- Neon API 友好,简化了手写 N-API 的繁琐工作
缺点:
- 需要在本地编译工具链,编译速度相对较慢
- 仅限于 Node.js 环境,不可直接用于浏览器
创建 Neon 项目
安装 Neon CLI(已全局安装可跳过):
npm install -g neon-cli
使用 neon-cli 创建项目:
neon new neon_example cd neon_example
该命令会自动生成一个包含 JavaScript 与 Rust Scaffold 的项目,目录结构类似:
neon_example/ ├── native/ # Rust 代码 │ ├── Cargo.toml │ └── src/ │ └── lib.rs # Rust 源文件 ├── package.json └── index.js # JS 入口,用于加载 .node 模块
安装依赖:
npm install
- Neon 会自动配置
bindings
、neon-runtime
、neon-build
等依赖。
- Neon 会自动配置
示例:在 Rust 中实现高性能计算并供 Node 调用
以“计算 Fibonacci 第 N 项”为示例,演示如何将 Rust 高性能递归/迭代实现暴露给 Node.js。
1. 编辑 Rust 源文件 native/src/lib.rs
// native/src/lib.rs
#[macro_use]
extern crate neon;
use neon::prelude::*;
/// 纯 Rust 实现:计算第 n 项 Fibonacci(迭代方式,避免递归爆栈)
fn fib(n: u64) -> u64 {
if n < 2 {
return n;
}
let mut a: u64 = 0;
let mut b: u64 = 1;
let mut i = 2;
while i <= n {
let c = a + b;
a = b;
b = c;
i += 1;
}
b
}
/// Neon 函数:从 JavaScript 获取参数并调用 Rust fib,然后将结果返回给 JS
fn js_fib(mut cx: FunctionContext) -> JsResult<JsNumber> {
// 1. 从 JS 参数列表取第一个参数,转换为 u64
let n = cx.argument::<JsNumber>(0)?.value() as u64;
// 2. 调用 Rust fib
let result = fib(n);
// 3. 将结果包装为 JsNumber 返回
Ok(cx.number(result as f64))
}
/// Neon 模块初始化:将 js_fib 注册为名为 "fib" 的函数
register_module!(mut cx, {
cx.export_function("fib", js_fib)?;
Ok(())
});
#[macro_use] extern crate neon;
:启用 Neon 提供的宏。fn js_fib(mut cx: FunctionContext) -> JsResult<JsNumber>
:Neon 约定的 JS 函数签名,FunctionContext
带有调用信息。cx.argument::<JsNumber>(0)?
:取第 0 个参数并转换为JsNumber
,最后用.value()
得到 f64。register_module!
:Neon 宏,用于在 Node.js 加载时注册导出的函数。
2. 编辑 JavaScript 入口 index.js
// index.js
// `require` 会触发 Neon 在构建时生成的本地模块(目录名可能是 neon_example.node)
const addon = require('./native/index.node'); // 或者 require('neon_example')
// 调用导出的 fib 函数
function testFib(n) {
console.log(`Calculating fib(${n}) via Rust...`);
const result = addon.fib(n);
console.log(`Result:`, result);
}
testFib(40);
注意:native/index.node
的相对路径需与实际构建产物一致。Neon 默认会在native/target
下生成编译产物,并通过neon-build
脚本复制到与package.json
同级目录。
构建与使用
编译 Rust 代码
在项目根目录执行:npm run build
默认会触发 Neon 的构建脚本,等价于:
cd native cargo build --release # 生成 release 版本的 .so/.dylib/.dll
然后 Neon 将自动拷贝生成的
.node
文件到顶层,以便require('./native/index.node')
。运行示例
node index.js
输出类似:
Calculating fib(40) via Rust... Result: 102334155
与纯 JS 递归或迭代相比,Rust 实现常常更快,尤其在
n
较大时优势明显。
Neon 调用流程图解
下面用 ASCII 图示说明一次从 Node.js 到 Rust 的调用流程:
┌─────────────────────┐
│ Node.js 进程 │
│ (JavaScript 层) │
└─────────┬───────────┘
│ require('neon_example')
▼
┌─────────────────────┐
│ Neon 生成的 .node │ <--- Node.js 动态加载本地模块
│ (动态库/DLL/.so) │
└─────────┬───────────┘
│ C++ FFI(N-API / V8 API)
▼
┌─────────────────────────┐
│ 注册的 Rust 函数 (js_fib)│
│ (通过 Neon 宏映射) │
└─────────┬───────────────┘
│ 调用 Rust fib(n)
▼
┌───────────────────────────┐
│ Rust 逻辑层 (fib) │
│ (纯 Rust 高性能计算) │
└─────────┬─────────────────┘
│ 返回结果 (u64)
▼
┌───────────────────────────┐
│ Neon 转换结果为 JsNumber │
│ 并返回给 JS 上下文 │
└───────────────────────────┘
- Node.js
require()
触发加载本地.node
模块,底层使用 N-API/V8 API 调用 Neon 生成的初始化函数。 - Neon 在初始化时将
js_fib
注册给 V8,形成 JS 可调用的函数。 - Node.js 调用
addon.fib()
,Neon 将参数从JsNumber
转为原生类型,调用 Rust 函数fib
。 - Rust 逻辑完成后,将结果回传给 Neon,Neon 再将其封装为
JsNumber
返回给 JS。
方案二:使用 napi-rs 进行 N-API 绑定
napi-rs 简介
napi-rs 是一个基于 Rust 实现的框架,利用 Node.js N-API(Node.js 官方提供的 C 原生接口)来编写 Node.js 原生插件。与 Neon 相比,napi-rs 提供的 API 更贴近原生 N-API,但采用宏和 builder 模式,极大简化了手写 N-API 绑定的复杂度。
优点:
- N-API 保证了不同 Node.js 版本间的兼容性(ABI 稳定)。
- Rust 层代码风格统一,借助宏描述导出函数更简明。
- 支持异步方法(Promise 或回调)。
缺点:
- 学习成本稍高,需要理解 N-API 与 napi-rs 的宏系统。
创建 napi-rs 项目
安装 napi-rs CLI(若未全局安装):
npm install -g @napi-rs/cli
使用 napi-cli 创建项目:
napi init --name napi_example cd napi_example
该命令会创建一个基于 napi-rs 的模板项目,目录结构类似:
napi_example/ ├── bindings/ # JS 类型绑定(根据需要生成) ├── examples/ # 示例代码 ├── native/ # Rust 代码 │ ├── Cargo.toml │ └── src/ │ └── lib.rs ├── package.json ├── index.js # JS 入口 └── napi_build.sh / napi_build.cmd # 构建脚本
安装依赖:
npm install
- 项目会自动拉取
@napi-rs
相关依赖(napi
、napi-derive
、napi-build
等)。
- 项目会自动拉取
示例:Rust 实现异步文件哈希并在 Node 中使用
以读取文件并计算其 SHA-256 哈希为例,演示如何编写一个异步接口(返回 Promise)供 Node.js 调用。
1. 编辑 Rust 源文件 native/src/lib.rs
// native/src/lib.rs
use napi::{CallContext, Env, JsBuffer, JsObject, JsString, JsUndefined, Result, Task};
use napi::bindgen_prelude::ToNapiValue;
use napi_derive::napi;
use sha2::{Sha256, Digest};
use tokio::fs::File;
use tokio::io::{AsyncReadExt, BufReader};
/// 定义一个异步任务:读取文件并计算 SHA-256
pub struct HashTask {
pub path: String,
}
#[napi]
impl Task for HashTask {
type Output = String;
type JsValue = JsString;
/// 在 Rust 异步环境中执行计算
fn compute(&mut self) -> napi::Result<Self::Output> {
// 这里使用 tokio 提供的阻塞读取方式:在当前线程同步执行
// 为简化示例,不使用真正的 async/await
let runtime = tokio::runtime::Runtime::new().unwrap();
let path = self.path.clone();
runtime.block_on(async move {
// 打开文件
let file = File::open(&path).await.map_err(|e| napi::Error::from_reason(e.to_string()))?;
let mut reader = BufReader::new(file);
let mut hasher = Sha256::new();
let mut buf = vec![0u8; 1024 * 8];
loop {
let n = reader.read(&mut buf).await.map_err(|e| napi::Error::from_reason(e.to_string()))?;
if n == 0 {
break;
}
hasher.update(&buf[..n]);
}
let result = hasher.finalize();
Ok(format!("{:x}", result))
})
}
/// 将 Rust 计算结果转换为 JS 值
fn resolve(&mut self, env: Env, output: Self::Output) -> napi::Result<Self::JsValue> {
env.create_string(&output)
}
}
/// 导出一个函数:返回一个 Promise,内部封装了 HashTask
#[napi]
fn hash_file(ctx: CallContext) -> Result<JsObject> {
// 从第一个参数获取文件路径
let path = ctx.get::<JsString>(0)?.into_utf8()?.as_str()?.to_string();
let task = HashTask { path };
// 将任务转换为 Promise
ctx.env.spawn(task)
}
/// 导出同步函数:计算内存中数据的 SHA-256
#[napi]
fn hash_buffer(ctx: CallContext) -> Result<JsString> {
// 获取第一个参数:Buffer
let buffer: JsBuffer = ctx.get::<JsBuffer>(0)?;
let data = buffer.into_value()?;
let mut hasher = Sha256::new();
hasher.update(&data);
let result = hasher.finalize();
ctx.env.create_string(&format!("{:x}", result))
}
#[napi]
:标记要导出的函数或结构体。- 异步任务需实现
Task
trait,提供compute
(耗时操作)和resolve
(将结果返回 JS)。 ctx.env.spawn(task)
:将异步任务提交给 N-API,返回一个 JSPromise
。- 同步方法
hash_buffer
直接将Buffer
数据提取为Vec<u8>
,计算哈希后立即返回JsString
。
2. 编辑 JavaScript 入口 index.js
// index.js
const { hash_file, hash_buffer } = require('./native'); // 默认加载本地编译的包
async function testHash() {
const filePath = './example.txt';
console.log(`计算文件 ${filePath} 的 SHA-256 哈希...`);
try {
const hash1 = await hash_file(filePath);
console.log('文件哈希:', hash1);
} catch (err) {
console.error('hash_file 错误:', err);
}
const data = Buffer.from('Hello, napi-rs!');
console.log('计算内存 Buffer 的哈希...');
const hash2 = hash_buffer(data);
console.log('Buffer 哈希:', hash2);
}
testHash();
注意:编译后产物会自动放置到native/index.node
,require('./native')
会加载并导出hash_file
、hash_buffer
。
构建与使用
在项目根目录执行:
npm run build
或根据
package.json
中的脚本:napi build --release
napi build
会触发cargo build --release
并将.node
文件生成到native
目录下。
运行示例:
node index.js
输出示例:
计算文件 ./example.txt 的 SHA-256 哈希...
文件哈希: 5f70bf18a08660e5d5e4960e2950d3b669cf7adaa...
计算内存 Buffer 的哈希...
Buffer 哈希: e8e9b7cd4a4b9f2f9ed5a5d1fd7b7c3a72fbece49a...
napi-rs 调用流程图解
下面用 ASCII 示意 Rust 与 Node.js 之间的异步调用流程:
┌────────────────────────────────────────┐
│ Node.js 进程 │
│ (JavaScript 层,调用 hash_file()) │
└────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────┐
│ napi-rs 生成的 .node 模块 │
│ (基于 N-API 注册 hash_file、hash_buffer)│
└────────────────────────────────────────┘
│
---------- 同步调用 / 生成 Promise --------
│ │
▼ ▼
┌──────────┐ ┌───────────────────┐
│ hash_buffer │ ──> Rust 同步计算 │
│ (JsBuffer) │ │ -> 返回 JsString │
└──────────┘ └───────────────────┘
▲
│
┌──────────────────────────────────┐
│ hash_file() │
│ (从 JS 获取 path,构造 HashTask) │
└──────────────────────────────────┘
│
▼
napi-rs spawn(Task) (返回 Promise)
│
▼
┌────────────────────────────────────────┐
│ N-API 将任务推入线程池(Rust 线程) │
└────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────┐
│ Rust 异步任务:读取文件并计算哈希 │
│ (Tokio Runtime + sha2) │
└────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────┐
│ Rust resolve() -> 将结果包装成 JsString│
│ N-API 通知 JS Promise 完成 │
└────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────┐
│ Node.js 层 await hash_file() 拿到结果 │
└────────────────────────────────────────┘
- JS 调用
hash_file(path)
,napi-rs 建立HashTask
并返回一个 Promise。 - 底层 N-API 将任务提交给 Rust 的线程池执行,直到完成后通过回调
resolve
将结果传回 JS。 - 同步函数
hash_buffer
则是同步执行,直接返回JsString
。
方案三:基于 WebAssembly (wasm-bindgen) 的跨平台互操作
Wasm + wasm-bindgen 简介
- WebAssembly (Wasm):一种二进制格式,可在浏览器、Node.js、嵌入式环境等多种平台以接近原生速度运行。
- wasm-bindgen:Rust 官方项目,用于在编译 Rust 为 Wasm 模块时自动生成 JS 绑定,简化 Rust 与 JS 之间的数据互相传递。
这种方式将 Rust 代码编译为 .wasm
文件,并自动生成一份 JS 封装(或通过工具链手动编写加载代码)。在 Node.js 中,可以像加载普通模块一样加载 Wasm 模块,并调用其中的导出函数。
优点:
- 跨平台复用:同一份
.wasm
可同时在浏览器和 Node.js 中使用。 - 分发简便:只需发布
.wasm
与 JS 封装,无需原生编译环境。
- 跨平台复用:同一份
缺点:
- 性能开销:虽然接近原生,但相比直接编译为本地动态库稍有损耗。
- 功能受限:Wasm 环境下无法直接使用系统级 API(如文件 I/O、线程等,需要通过 JS 做桥接)。
创建 wasm-bindgen 项目
安装 wasm-pack(Rust-Wasm 工具链):
cargo install wasm-pack
创建 Cargo 项目:
cargo new --lib wasm_example cd wasm_example
添加依赖
在Cargo.toml
中添加:[dependencies] wasm-bindgen = "0.2"
配置
lib.rs
// src/lib.rs use wasm_bindgen::prelude::*; // 导出一个简单函数:字符串反转 #[wasm_bindgen] pub fn reverse_string(s: &str) -> String { s.chars().rev().collect() } // 导出一个更复杂的例子:压缩字符串(简单 RLE 算法示例) #[wasm_bindgen] pub fn rle_compress(s: &str) -> String { let mut result = String::new(); let mut chars = s.chars().peekable(); while let Some(c) = chars.next() { let mut count = 1; while chars.peek() == Some(&c) { chars.next(); count += 1; } result.push(c); result.push_str(&count.to_string()); } result }
#[wasm_bindgen]
:标记要导出到 JS 的函数或结构体。
构建与使用
使用 wasm-pack 构建
在项目根目录执行:wasm-pack build --target nodejs
--target nodejs
表示生成的包用于 Node.js 环境(而非浏览器)。构建完成后,会在
pkg/
目录下生成:pkg/ ├── wasm_example_bg.wasm # WebAssembly 二进制 ├── wasm_example.js # JS 封装,自动加载 .wasm ├── package.json └── ...
在 Node.js 中加载使用
在项目根目录创建一个新目录或在同一项目下新建node_test/
:node_test/ ├── index.js └── package.json
执行:
cd node_test npm init -y npm install ../wasm_example/pkg
npm install ../wasm_example/pkg
会将刚才生成的 wasm 包安装到 Node.js 项目中。
编辑
index.js
// node_test/index.js const { reverse_string, rle_compress } = require('wasm_example'); function testWasm() { const s = 'aaabbbbccddddd'; console.log('Original:', s); console.log('Reversed:', reverse_string(s)); console.log('RLE Compressed:', rle_compress(s)); } testWasm();
运行
node index.js
你会看到:
Original: aaabbbbccddddd Reversed: ddddccb bbbaaa RLE Compressed: a3b4c2d5
Wasm 调用流程图解
┌──────────────────────────┐
│ Node.js 进程 │
│ (JavaScript 层) │
└─────────┬────────────────┘
│ require('wasm_example')
▼
┌──────────────────────────┐
│ wasm_example.js (JS 封装) │
│ - 加载 wasm_example_bg.wasm │
│ - 提供 JS 闭包函数 │
└─────────┬────────────────┘
│
▼
┌──────────────────────────┐
│ wasm_example_bg.wasm │ <--- WebAssembly 二进制
├──────────────────────────┤
│ - WebAssembly 实例化 │
│ - 提供底层计算逻辑 │
└─────────┬────────────────┘
│
▼
┌──────────────────────────┐
│ Wasm 运行时执行 Rust 代码 │
│ (字符串反转 / RLE 压缩) │
└──────────────────────────┘
│
▼
┌──────────────────────────┐
│ 将结果通过 JS 封装返回 │
└──────────────────────────┘
- Node.js
require
会执行wasm_example.js
,自动加载并实例化.wasm
,将导出函数包装成 JS 可调用的同步或异步方法。 - JS 直接调用如
reverse_string("hello")
,底层会调用 Wasm 实例的导出函数,并立即返回结果。
性能对比与注意事项
方案 | 性能 | 兼容性 | 开发复杂度 | 典型场景 |
---|---|---|---|---|
Neon | 最高(接近原生) | 仅限 Node.js | 中等 | CPU 密集型计算,需极致性能 |
napi-rs | 极高(基于 N-API) | 仅限 Node.js | 较低 | 需兼容多 Node.js 版本,异步任务、I/O 密集场景 |
Wasm | 较高(比 Neon 略慢) | 跨 Node.js / 浏览器 | 较低 | 跨平台复用、前后端共享算法、打包分发 |
编译体积
- Neon 与 napi-rs 会生成较大的动态库,尤其包含 Rust 标准库时;
- Wasm 打包相对较小,适合前端与后端共同使用。
调试与开发体验
- Neon 代码与项目紧密耦合,需要 Rust 编译环境;
- napi-rs 与 Neon 相似,但 N-API 的 ABI 稳定性让兼容性更好;
- Wasm 需要额外理解 Wasm 模块加载与异步性。
数据传输成本
- Neon 与 napi-rs 在 Rust 与 JS 之间传递数据直接基于本地内存,可高效传输大段二进制;
- Wasm 在 JS 与 Wasm 内存之间复制数据,若传输大数组需注意性能。
安全性考量
无论哪种方式,都需关注以下安全性要点:
输入校验
- 从 JS 层传入 Rust 层的参数必须严格检查类型与有效性,避免越界读写。
内存泄漏
- Neon 与 napi-rs 的绑定代码会自动管理大多数内存,但若手动分配 Buffer 或使用 unsafe 代码,需确保互相释放;
- Wasm 需注意调用
wasm_bindgen::memory()
时对内存的管理,避免多次分配而未释放。
错误处理
- Rust 层应尽量使用
Result
处理错误,并通过 Neon 或 napi-rs 将错误信息传递给 JS 层,而不是 panic。 - Wasm 层可通过
wasm-bindgen
的throw_str
抛出异常,但要注意在 JS 侧捕获。
- Rust 层应尽量使用
依赖审计
- Neon 与 napi-rs 项目会拉入一些 C/C++ 依赖(如 N-API 源码),需定期更新以修复安全漏洞;
- Wasm 项目同样需审查 Rust crates 的安全级别。
总结与实践建议
本文围绕 Rust 与 Node.js 互操作,系统介绍了三种主要实践路径:
Neon
- 适合对性能要求极致、仅限 Node.js 环境的场景。需安装 Neon CLI、Rust 编译环境,编写少量 Neon 宏代码,即可将 Rust 函数暴露给 JS 调用。
napi-rs
- 基于 Node.js 官方 N-API,ABI 稳定性好,兼容多版本,支持同步与异步接口。通过 Rust 宏(
#[napi]
、Task
)简化绑定,适合需要异步任务(Promise)或依赖 N-API 生态的项目。
- 基于 Node.js 官方 N-API,ABI 稳定性好,兼容多版本,支持同步与异步接口。通过 Rust 宏(
WebAssembly (wasm-bindgen)
- 可在 Node.js 与浏览器中复用同一份 Rust 逻辑,打包体积较小。适合前后端共享算法、跨平台分发与轻量级性能提升场景。
在实际项目中,可根据需求权衡选择:
- 如果只关注 Node.js 性能,且可接受较大编译体积,则首选 Neon 或 napi-rs。
- 如果需要前后端共享业务逻辑(如图像处理、加密算法),则应选择 Wasm,并结合 Node.js 加载。
- 在 CPU 密集且需要异步文件 I/O、Future/Promise 结合的场景,napi-rs 的异步 task 支持更好;
- 在需要同时兼容浏览器、Electron、Node.js 的代码库,尽量将核心逻辑封装为 Wasm,配合 wasm-bindgen 生成 TS/JS 绑定。
至此,你已了解从零开始在 Node.js 中集成 Rust 代码的多种路径,并通过示例代码与图解掌握了基本原理与操作流程。希望本文能帮助你在项目中构建高性能且安全的 Rust + Node.js 混合应用,发挥两者的最佳优势。
评论已关闭