WebAssembly 调试
问题
如何调试 Rust 编译到 WebAssembly 的应用?
答案
Wasm 调试挑战
| 挑战 | 说明 |
|---|---|
| 无 stdout | Wasm 无法直接 println! |
| 堆栈信息受限 | panic 信息默认被裁剪 |
| 内存不透明 | JS 侧看不到 Wasm 内存细节 |
| Source Map 有限 | DWARF 调试信息支持尚不完善 |
基础调试:console_log
use wasm_bindgen::prelude::*;
// 绑定 JS 的 console.log
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
// 方便的宏
macro_rules! console_log {
($($t:tt)*) => (log(&format!($($t)*)))
}
#[wasm_bindgen]
pub fn process_data(input: &str) -> String {
console_log!("输入: {}", input);
let result = input.to_uppercase();
console_log!("结果: {}", result);
result
}
使用 console_error_panic_hook
Cargo.toml
[dependencies]
console_error_panic_hook = "0.1"
wasm-bindgen = "0.2"
use wasm_bindgen::prelude::*;
/// 初始化时注册 panic hook,使 panic 信息输出到浏览器控制台
#[wasm_bindgen(start)]
pub fn init() {
console_error_panic_hook::set_once();
}
#[wasm_bindgen]
pub fn divide(a: f64, b: f64) -> f64 {
if b == 0.0 {
panic!("除以零: a={}, b={}", a, b);
// 有了 panic hook,浏览器控制台会显示完整堆栈
}
a / b
}
使用 tracing-wasm
use tracing::{info, warn, instrument};
use tracing_wasm::WASMLayerConfigBuilder;
#[wasm_bindgen(start)]
pub fn init() {
let config = WASMLayerConfigBuilder::default()
.set_max_level(tracing::Level::DEBUG)
.build();
tracing_wasm::set_as_global_default_with_config(config);
}
#[instrument] // 自动记录函数入参和耗时
#[wasm_bindgen]
pub fn compute(n: u32) -> u32 {
info!("开始计算");
let result = fibonacci(n);
info!(result, "计算完成");
result
}
浏览器 DevTools 调试
# 构建时保留调试信息
wasm-pack build --debug
# 或在 Cargo.toml 中配置
[profile.dev]
opt-level = 0 # 不优化
debug = true # 保留 DWARF 调试信息
Chrome DevTools 中可以在 Sources 面板看到 .wasm 文件,配合 DWARF 插件可以设断点。
wasm-bindgen-test 测试
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
fn test_greet() {
let result = greet("World");
assert_eq!(result, "Hello, World!");
}
#[wasm_bindgen_test]
async fn test_async_fetch() {
let data = fetch_data().await;
assert!(!data.is_empty());
}
# 在浏览器或 Node 中运行 wasm 测试
wasm-pack test --chrome --headless
wasm-pack test --node
常见面试问题
Q1: Wasm 中 panic 该如何处理?
答案:
- 使用
console_error_panic_hook将 panic 信息输出到 Console - 生产环境设置
panic = "abort"减小体积 - 在关键入口用
std::panic::catch_unwind捕获,转为 JS 错误 - 优先使用
Result而非 panic
Q2: 如何分析 Wasm 的包体积?
答案:
twiggy工具分析.wasm文件各符号大小wasm-opt -Oz优化体积wee_alloc替换默认分配器(减少约 10KB)cargo bloat --target wasm32-unknown-unknown查看函数体积